Movatterモバイル変換


[0]ホーム

URL:


laiso
Sign inSubscribe

site2skill: どんなサイトでもClaude Skills化するツールを作った

任意のWebドキュメントをClaudeAgent Skills化するツールsite2skill を作りました。PAY.JPのドキュメントを例に、Claude Codeがドキュメントを参照しながら開発する流れを説明します。

GitHub - laiso/site2skill
Contribute to laiso/site2skill development by creating an account on GitHub.
GitHublaiso

LLMが知らないライブラリを使うとき

LLMには知識のカットオフ(学習データの期限)があります。新しいライブラリやマイナーなAPIを使おうとすると、LLMは正確な情報を持っていません。例えばClaude Opus 4.5 の知識は2025年8月のものであり、それ以降にリリースされたライブラリや、学習データに含まれていないドキュメントについては、正確なコードを生成できません。

こういう場面では、Webのドキュメントを要約してチャットに貼り付け、それをもとに実装してもらうという作業を繰り返すことになります。この方法は有効ですが、毎回ドキュメントを探して貼り付ける手間がかかります。プロジェクトが進むにつれて、同じドキュメントを何度も貼り付けることになり非効率です。

既存の解決策として、URLから都度取り込む方法(WebFetchやWebSearch)や、ドキュメント検索に対応したMCPサーバーを使う方法があります。MCP(Model Context Protocol)はAnthropicが提唱するAIとツールの連携プロトコルで、StripeなどはMCPサーバーを公式に提供しています。さらに、Upstashが提供するContext7 MCPサーバー のように、最新ドキュメントをスニペットでリアルタイムでLLMに供給する仕組みも登場しています。

ただし、MCPサーバー経由で提供されていないサービスでは使えません。PAY.JPのような国内サービスや、マイナーなライブラリには対応するMCPサーバーがないことが多いです。

ClaudeにはAgent Skills という仕組みがあります。Agent Skillsは必要なときだけ読み込まれる専門知識モジュールで、ユーザー側で任意のドキュメントをエージェントの知識として組み込めます。すべての情報を常時プロンプトに含めるのではなく、Claudeが必要と判断した際に読み込むため、トークン消費を抑制できる設計になっています。

Equipping agents for the real world with Agent Skills
Discover how Anthropic builds AI agents with practical capabilities through modular skills, enabling them to handle complex real-world tasks more effectively and reliably.

ただし、これを使ってドキュメント参照のSkillを手作業で作るには、LLMが読み込みやすいようにHTMLをMarkdownに変換してクリーンにしたり、ディレクトリ構造を整え、参照方法を手続き化してSKILL.mdに明記する必要があります。

そこで作ったのがsite2skill です。WebサイトをローカルにダウンロードしてClaude Skillsで検索可能にする変換ツールで、Pythonで開発しています。1コマンドで任意のドキュメントサイトを現在のディレクトリで有効なSkillにインポートできます。

site2skillの使い方

site2skillは以下のコマンドで実行します。uvxはPythonパッケージ管理ツールuvに含まれるコマンドで、パッケージを一時的にインストールして実行できます。

❯ uvx --from git+https://github.com/laiso/site2skill site2skill https://docs.pay.jp/v1/ payjp

このコマンドはhttps://docs.pay.jp/v1/配下のページを再帰的にダウンロードし、payjpという名前のSkillを生成します。出力は2形式あり、Claude Code用の.claude/skills/payjp/ディレクトリ(デフォルト)と、Claudeデスクトップアプリ用のpayjp.skillファイル(ZIP形式)が生成されます。ディレクトリ形式はClaude Codeがそのまま読み込め、.skillファイルはClaudeデスクトップアプリにドラッグ&ドロップでインストールできます。

site2skillの実行ログは以下のようになります。

❯ uvx --from git+https://github.com/laiso/site2skill site2skill https://docs.pay.jp/v1/ payjp2025-12-16 11:36:14,351 - INFO - === Step 1: Fetching https://docs.pay.jp/v1/ ===2025-12-16 11:36:14,352 - INFO - Fetching https://docs.pay.jp/v1/ to build/download/crawl...2025-12-16 11:36:14,352 - INFO - Domain restricted to: docs.pay.jp[53 pages | 1m21s | 0.6/s] https://docs.pay.jp/v1/api/2025-12-16 11:37:36,111 - INFO - Download complete. 53 pages in 1m21s.# ...2025-12-16 11:37:41,933 - INFO - === Step 6: Packaging Skill ===Packaging .claude/skills/payjp to ./payjp.zip...Successfully created: ./payjp.skill2025-12-16 11:37:41,957 - INFO - === Done! ===2025-12-16 11:37:41,957 - INFO - Skill directory: .claude/skills/payjp2025-12-16 11:37:41,957 - INFO - Skill package: ./payjp.skill2025-12-16 11:37:41,957 - INFO - Temporary files kept in build

生成されるディレクトリ構造は以下の通りです。

payjp/├── SKILL.md           # Skillの定義(descriptionで自動読み込みを制御)├── docs/              # 変換されたMarkdownドキュメント└── scripts/    └── search_docs.py # 全文検索ツール

SKILL.mdはSkillの定義ファイルで、descriptionフィールドに記載された内容をClaudeが読み、ユーザーのリクエスト内容とマッチするかを判断します。docs/には変換されたMarkdownドキュメントが格納され、search_docs.pyは全文検索用のスクリプトです。

Skillの自動読み込みはSKILL.mddescriptionフィールドで制御します。

❯ head .claude/skills/payjp/SKILL.md---name: payjpdescription: PAYJP documentation assistant---# PAYJP SkillThis skill provides access to PAYJP documentation.## Documentation

このように設定され、ユーザーが「PAY.JPで決済機能作って」と言ったときにSkillが読み込まれます。スラッシュコマンド(/command)のような明示的な呼び出し不要で、Claudeが自動的に判断します。

実際の開発フローは4ステップです。まずSkillを.claude/skills/payjpに設置し、Claude Codeを起動します。次に「PAY.JPでサブスク実装して」のようにリクエストすると、Skillが自動的に読み込まれます。Claudeはドキュメントを参照しながらコードを生成し、レビューと動作確認を経て実装が完了します。ドキュメントを毎回貼り付ける必要がなくなり、開発効率が上がります。

デモ:PAY.JPで単発決済を実装する

実際にSkillを使ってコードを生成する様子を示します。既存のNext.js プロジェクトでカート決済のAPIを実装します。

Claude Codeを起動して「PAY.JPでカート決済のAPIを作って」とリクエストすると、以下のようにSkillが確認され、読み込まれます。

> PAY.JPでカート決済のAPIを作って Use skill "payjp"? Claude may use instructions, code, or files from this Skill.   PAYJP documentation assistant (project) Do you want to proceed? ❯ 1. Yes   2. Yes, and don't ask again for payjp in /tmp/site2skill   3. No, and tell Claude what to do differently (esc)

ClaudeはSkillのsearch_docs.pyを使ってドキュメントを検索し、Charge APIの使い方を把握した上でコードを生成します。

⏺ Skill(payjp)∴ Thinking…  PAY.JPのスキルが起動しました。カート決済のAPIを作成するために、まず:  1. PAY.JPのドキュメントを検索して決済に関する情報を取得  2. 現在のコードベースの構造を理解  3. 実装計画を立てる  まずはPAY.JPのドキュメントを検索し、同時にコードベースの構造を確認しましょう。⏺ PAY.JPのドキュメントを検索し、コードベースの構造を確認します。                                                                                                                                                                   11:48 AM  claude-opus-4-5-20251101⏺ Bash(python /tmp/site2skill/.claude/skills/payjp/scripts/search_docs.py "charge 決済 支払い")  ⎿ Search Results for 'charge 決済 支払い'    Found matches in 10 files.    1. docs/api.md       Matches: 447 | Source: "https://docs.pay.jp/v1/api"       Fetched: "2025-12-04T08:54:19.094053+00:00"    ----------------------------------------      # PAY.JP API    > PAY.JP は、RESTをベースに構成された決済APIです。都度の支払い、定期的な支払い、顧客情報の管理など、ビジネス運用における様々なことができます。

以下のようなそれっぽい画面を作ってくれました。

// pages/api/checkout.tsexport default async function handler(  req: NextApiRequest,  res: NextApiResponse<ChargeResponse | ErrorResponse>) {  if (req.method !== "POST") {    res.setHeader("Allow", ["POST"]);    return res.status(405).json({ error: "Method Not Allowed" });  }  const { token, cart, description } = req.body as CheckoutRequest;  if (!token) {    return res.status(400).json({ error: "Token is required" });  }  if (!cart || cart.length === 0) {    return res.status(400).json({ error: "Cart is empty" });  }  const amount = cart.reduce(    (total, item) => total + item.price * item.quantity,    0  );  if (amount < 50) {    return res.status(400).json({ error: "Minimum amount is 50 JPY" });  }  try {    const charge = await payjp.charges.create({      card: token,      amount,      currency: "jpy",      description: description || `Cart checkout - ${cart.length} items`,    });    return res.status(200).json({      id: charge.id,      amount: charge.amount,      currency: charge.currency,      paid: charge.paid,    });  } catch (error: unknown) {    console.error("PAY.JP charge error:", error);    const payjpError = error as { message?: string; status?: number };    return res.status(payjpError.status || 500).json({      error: "Payment failed",      details: payjpError.message,    });  }}

​テストカードを入力し決済が成功すると以下のようなメッセージが表示されます。

決済が完了しました決済ID: ch_5e69XXXX合計金額: ¥2,500

このように、Skillがあればドキュメントを貼り付けなくても、ClaudeがAPIの仕様を理解してコードを生成できます。

コードレビューにも活用する

さて、一見これでプロトタイプが作れそうですがせっかくClaude Codeを使っているので生成したコードについて/security-review でセルフチェックしてもらいましょう。バイアスを除去するために一旦セッションをクリアして実行しました。作成したSkillはレビュー時にも呼び出してくれました。

⏺ 3つの検証結果が返りました:  1. 価格改ざん脆弱性: 信頼度スコア 10/10 - 確認済みの脆弱性  2. エラー詳細の露出: 信頼度スコア 4/10 - False Positive(閾値8未満のため除外)  3. 負の数値検証: 信頼度スコア 2/10 - False Positive(閾値8未満のため除外)

上記の3つの問題を検出しました。「価格改ざん脆弱性」というのはクライアントサイドから送信されたAmountを受け入れて決済している部分ですね。はい、実は生成されたコードを横目にした時に気づいていたのでレビューで見直してもらったのです。

修正を依頼したところ、サーバーサイドでインメモリに商品カタログ情報を持ち、IDを送信する実装に変わりました。エージェントが初期コードの生成だけではなく、既存コードの改修にもSkillでドキュメントを検索し適切に作業してくれます。人間が調査しながら問題に対応するのを自動化してなぞっているので当然ですね。

このようにsite2skillは該当のドメインを理解したコードレビューを行うのにも最適です。

開発以外にも使える

Claude Skillsはデスクトップアプリにもインポートできます。なので単にドキュメントについて対話で質問したい場合は作成された.skill をインポートして使うことができます。Claude Codeユーザー以外はこちらを使えます。クラウド上で実行されるため、検索のためにPythonのインストールをする必要もありません。

Setting > Capabilities > Skills からアップロードしてチャットする

site2skillの内部処理

ここからは技術記事らしく、site2skillの実装について説明します。ツールの利用だけが目的であれば、このセクションは読み飛ばして構いません。

site2skillは5段階で処理を行います。まずwgetで対象サイトを再帰的にダウンロードします。--level=5--wait=1オプションを指定し、robots.txtを遵守することで、対象サイトへの負荷を抑えています。次にBeautifulSoupでHTMLを解析し、markdownifyライブラリでMarkdownに変換します。HTMLタグやスタイル情報が除去されるため、コンテキスト量(LLMに渡すテキスト量)を削減できます。

3段階目でリンクを正規化します。相対パスを絶対パスに変換することで、Claudeが回答時にオリジナルドキュメントへのリンクを提示できるようになります。4段階目でSkill構造を自動生成し、SKILL.mddocs/ディレクトリを作成します。最後に検索ツールsearch_docs.pyを同梱します。

検索スクリプトを専用で実装した理由は2つあります。1つ目は、マッチ数でソートして関連度の高いドキュメントを優先表示するためです。単純なgrepripgrepではマッチした順に結果が返されますが、専用スクリプトではマッチ数が多いファイルを上位に表示します。2つ目は、フロントマター(Markdownファイル先頭のYAMLメタデータ)からsource_urlを抽出し、回答時にオリジナルドキュメントへのリンクを提示できるようにするためです。

着想の元

site2skillを作るにあたり、同様の課題に取り組んでいる既存のプロジェクトを参考にしました。

mastra/mcp-docs-serverは、AIアシスタントがMastraのナレッジベースに直接アクセスできる専用MCPサーバーです。.docs/raw/ディレクトリにドキュメントをローカル保存し、npmパッケージとして配布しています。site2skillとの違いは動作形態にあります。MastraはMCPサーバーとしてローカルのプロセスで動作しますが、site2skillは静的ファイルを生成するだけでMCPプロトコルは不要です。共通点は「ドキュメントをパッケージ化してAIに渡す」という発想です。

項目Mastrasite2skill
動作形態MCPサーバー(stdout)Claude Skills
配布形式npmパッケージ.skill形式。.claude/以下に展開

また、TypeScript CLIライブラリkazupon/gunshiは、ドキュメントをnpmパッケージ(@gunshi/docs)として配布するアプローチを取っています。./node_modules/@gunshi/docsという予測可能なパスでエージェントがアクセスでき、ライブラリ本体とドキュメントのバージョンを同期できます。MCPの制約(サーバーの登録上限、ツール定義によるコンテキスト消費、情報取得のたびにAPI呼び出しが必要になる問題)を回避できる点が特徴です。詳細は以下の記事を参照してください。

ドキュメントをnpm packageとしてpublishしよう | blog
Portfolio of @ryoppippi
sveltekit-prerenderryoppippi

応用と制限事項

site2skillは他のWeb公開ドキュメントにも応用できます。AWS、Google Cloud、各種ライブラリのドキュメントサイトを対象にSkillを生成できます。実行元からwgetでアクセスできる用件を満たせば、社内API(Swagger UIなど)にも適しており、APIが増えてもsite2skillを再実行するだけで更新できます。

しかしsite2skillは試験的なバージョンとして公開しています。今後、他にもより良い解決策が出てくる可能性もあります。

既知の課題として、wgetへの依存があります。Windows環境ではwgetを別途インストールするか、WSL(Windows Subsystem for Linux)を使用する必要があります。また、並列ダウンロードはあえて実装していません。対象サイトへの負荷を軽減するため、--wait=1オプションで1秒間隔を空けています。そのため、大規模サイトでは数十分など時間がかかります。

まとめ

site2skillの試みは、ドキュメントを「エージェントのローカル知識」として扱うことでした。エージェントのレイヤーから見た他の解決策とのアプローチの違いは以下です。

アプローチ知識の扱い特徴
MCP外部ツール必要な情報をその都度クエリで取得
RAG検索インデックスベクトル検索で関連文書を推定取得
site2skillローカル知識ファイルとスクリプトを直接参照

MCPは専用のツールで都度問い合わせが必要であり、(広義)RAGはベクトル検索で類似文書を取得する方式です。site2skillはドキュメントをパッケージ化してローカルに配置するため、サーバーや外部APIへの依存がありません。Claude自身がドキュメントを検索しながら作業でき、ユーザーがドキュメントに誘導する手間を省けます。

おまけ:NotebookLMに取り込むには?

姉妹ツールsite2pdfをお試しください。これはブラウザが描画した視覚情報をそのまま取り込むのでよりRAGシステム向きです。

GitHub - laiso/site2pdf: Generate comprehensive PDFs of entire websites, ideal for RAG.
Generate comprehensive PDFs of entire websites, ideal for RAG. - laiso/site2pdf
GitHublaiso

この記事は「PAY Advent Calendar 2025」の20日目です

オンライン決済サービスPAY.JPを使ってみた情報をシェアしよう! by PAY - Qiita Advent Calendar 2025 - Qiita
Calendar page for Qiita Advent Calendar 2025 regarding オンライン決済サービスPAY.JPを使ってみた情報をシェアしよう! by PAY.
Qiita

Subscribe to laiso

Sign up now to get access to the library of members-only issues.
Jamie Larson
Subscribe

[8]ページ先頭

©2009-2025 Movatter.jp