すでに MCP を使ってモデルをデータベース、ファイルシステム、サードパーティ API に接続しているなら、おそらく次にもっと厄介な問題に直面するでしょう。ツールはすべて接続されたのに、モデルは依然として、ある物事をどの順序で、どの基準で完了すべきかを知らないのです。まさにこれが、Agent Skills(エージェントスキル)が埋める層です。これは Anthropic によって 2025 年 10 月に提唱され、その後オープン標準として agentskills.io に定着し、2026 年までには Codex、GitHub Copilot、Microsoft Agent Framework などのプラットフォームによって同じフォーマットで互換対応されています。本稿は「Agent Skills 完全ガイド」の前半部分です。まず土台を固めましょう。SKILL.md のフィールドの厳格な制約、フォルダディレクトリの規約、段階的開示の三層ロード順序、Token 予算の台帳的思考、そして最も見落とされやすい中核原則——コードで判断できることは、決して文字でモデルに請わない

MCP から Agent Skills へ:Anthropic の第二層の抽象化と 2025 年 10 月の起点

Skills の位置づけを理解するには、MCP と対照して見るのが最適です。MCP(Model Context Protocol)が解決するのは「外部ツールとデータソースにどう接続するか」であり、関心があるのはチャネルの問題です。モデルが検索インターフェースを呼べるか、データベースを読めるか、ある SaaS の API にアクセスできるか。しかしチャネルが開通したからといって、タスクが完了するわけではありません。実際の業務アクションには、判断、順序、フォーマット、境界検証、失敗時のリトライなど、一連の手続き的決定がしばしば含まれ、これらの決定を MCP 自体は担いません。

そこで Anthropic は 2025 年 10 月に Agent Skills を提唱し、それを MCP に続く第二層の抽象化と定義しました。MCP は「ツールがどこにあり、どう呼ぶか」に答え、Skills は「ツールを手に入れた後、この物事はどうすればうまくやったことになるのか」に答えます。一方は食材を厨房に運び込み、もう一方はレシピと火加減を示す役割です。両者は補完関係にあり、代替関係ではありません。Skills の公式ドキュメントでも、コード実行の安全性、安定性、サンドボックス分離において、MCP のようなサーバー側でホストされる実行方式が依然として優位に立つと明記されています。Skill はより軽量なスクリプトと単純なロジックに適しています。

特筆すべきはそのテンポです。提唱から約二か月後、Anthropic はこの仕様を自社製品の中に閉じ込めるのではなく、オープン標準として公開しました。どの Agent プラットフォームでも、このフォーマットに従って解析できれば、他人が書いた Skill と互換できます。この決定が、後で述べるクロスプラットフォームの版図を直接決めました。

オープン標準の定着:agentskills.io と Codex、Copilot、Microsoft Agent Framework の互換版図

2026 年までに、Agent Skills の位置づけは「Claude の一機能」からクロスプラットフォームのオープン標準へと進化し、公式仕様サイトは agentskills.io です。現在、同じフォーマットで Skill をサポートするプラットフォームには、Claude Code、OpenAI Codex、GitHub Copilot、Microsoft Agent Framework などがあります。これはつまり、Claude Code 用に書いた Skill フォルダは、理論上そのまま Codex や Copilot の skills ディレクトリに投入して再利用できるということです。ただし、あるプラットフォーム固有のメタデータ拡張に依存していない場合に限ります。

その中で個別に取り上げる価値があるのが Microsoft Agent Framework の設計です。これは Skill の能力を二つの明示的なアクションに分解します。read_skill_resource(リソースを読む)run_skill_script(スクリプトを実行する)です。この二分は気まぐれに付けられた名前ではなく、まさに後で繰り返し強調する中核メカニズムです。「読む」は内容をコンテキストに流し込み、Token を消費します。「実行する」はただ実行し、結果だけを取るので、ほとんどコンテキストを占めません。フレームワークがこの区別を一等市民に引き上げることは、実行時にあなたにこう考えさせるのと同じです。このステップは Agent に知らせるべきなのか、それとも Agent に実行させるべきなのか。

比較軸MCPAgent Skills
答える問い外部ツールとデータソースにどう接続するかツールを手に入れた後、どう正しくうまくやるか
抽象化の階層第一層(接続層)第二層(手続き的知識層)
典型的な担い手プロトコル + サーバー側プロセスフォルダ + SKILL.md
実行の安全性比較的高い。サーバー側サンドボックスでホスト可能比較的低い。スクリプトはローカルコンテキストで実行
適する複雑度重いロジック、強い分離が必要なタスク軽量スクリプトと単純なロジック
コンテキストのオーバーヘッドツール schema が常駐メタデータが約 100 tokens/skill で常駐

Skill の本質:フォルダ一つと SKILL.md 一つで、カプセル化するのは手続き的知識

Skill の物理的形態を突き詰めて言えば、実に一言です。フォルダ一つ + Markdown ファイル一つ(SKILL.md)。このフォルダに入っているのは手続き的知識(procedural knowledge)、つまり「どうやるか」です。事実的知識(declarative knowledge)、つまり「何であるか」は意図的に入れません。

この区別は非常に重要です。なぜなら、Skill を書くときの取捨選択の基準を決めるからです。事実的知識——会社の製品パラメータ、API のフィールドの使い方、ある領域の背景概念——は、検索システム、ドキュメントサイト、あるいは references/ に置いて必要に応じて取り出すべきです。一方、Skill が入れるべきはプロセス、手順、判断ルール、よくある落とし穴です。例えば、「当社の返金ポリシーは 7 日間無条件」は事実的知識で、ドキュメントに置くのに適しています。「返金紛争を処理するときは、まず注文時刻を確認し、7 日を超えていれば開封動画のアップロードを求め、そうでなければそのまま承認する」は手続き的知識で、これこそ Skill が担うべき内容です。

さらに言えば、手続き的知識の中で、確定的なコードで表現できるものは、自然言語で表現すべきではありません。これは全編で最も直感に反し、最も価値のある原則であり、後で一小節を割いて詳しく展開します。

ディレクトリ規約の分解:SKILL.md は必須、scripts/、references/、assets/ の三者は任意

公式に取り決められたディレクトリ構造は全部で四種類の内容ですが、必須なのは最初の一種類だけです。

  • SKILL.md(必須):Skill の入口。これがなければ、このフォルダは Skill ではありません。メタデータ宣言と主指令という二つの責務を担います。
  • scripts/(任意):実行可能コード。典型的な場面は検証、フォーマット、データ変換、ファイル生成です。その価値は「判断」を「実行」に変えることにあり、確定的エンジニアリングの着地点です。
  • references/(任意):オンデマンドの参考ドキュメント。API マニュアル、領域の背景、長大なルール表の置き場です。これは「読まれて」コンテキストに入るため、オンデマンドでロードされる重いリソースに属します。
  • assets/(任意):テンプレートと静的リソース。ファイルテンプレート、画像、フォント、サンプル出力など、スクリプトや Agent が直接利用するためのものです。

ここに初心者が最も陥りやすい落とし穴があります。あるディレクトリが Skill のルートディレクトリに当たるかどうかは、それが SKILL.md を直接含むかどうかで判断されます。多くの人は圧縮ファイルやリポジトリからダウンロードし、外側に同名のフォルダがあるのを見て丸ごとコピーしてしまいます。その結果、Agent が skills ルートディレクトリの下をスキャンして見つけるのは「サブフォルダの中のサブフォルダ」で、SKILL.md が見つからず、Skill がまったく効きません。正しいやり方は、ディレクトリツリーに入り、SKILL.md を直接含む階層を見つけ、その階層からコピーを始めることです。

SKILL.md の構造:YAML frontmatter メタデータ + Markdown 本文指令

SKILL.md は二つの部分をつなぎ合わせてできており、間を三本のハイフンで区切り、frontmatter はファイルの先頭に置かなければなりません。

  • メタデータ層(YAML frontmatter):Agent に「この Skill は何であり、いつ使うべきか」を伝えます。これは常にコンテキストにロードされ、常駐のオーバーヘッドです。
  • 指令層(Markdown 本文):Agent に「具体的にどう実行するか」を伝えます。これは Skill が起動された後にのみロードされます。

なぜ分けなければならないのか。両者のロードタイミングがまったく異なるからです。メタデータは「目次」であり、常にそこに存在しなければ、Agent が適切な瞬間にこの Skill を起動する価値があると発見できません。指令は「本文」であり、必要なときだけ展開されます。もし重要なトリガー情報を本文に書いてしまえば、それは永遠にロードされません—— —なぜなら、アクティベーション前は Agent が本文をまったく見ることができないからです。逆に、長い操作手順をメタデータに書き込んでしまうと、毎回の会話でその分の Token を支払うことになり、まったくの無駄です。

以下はそのまま流用できる SKILL.md の例で、frontmatter と本文がそれぞれの役割を担っています:

---
name: csv-schema-checker
description: CSV データのヘッダー、エンコーディング、列型を検証し、取り決めに反するデータ品質問題を検出する。ユーザーが CSV ファイルの形式を確認したり、汚いデータをクリーンアップしたり、アップロード前にデータ品質をチェックしたい場合に使用。
license: MIT
compatibility: Python 3.10 以上が必要。標準ライブラリの csv と chardet に依存
metadata:
  version: 1.2.0
  owner: data-platform
allowed-tools: Bash, Read
description_keywords: CSV, エンコーディング, ヘッダー, データ型, データ品質
---

# CSV データ品質検証

## いつ使うか

ユーザーが CSV ファイルの形式とデータ品質の確認、クリーンアップ、または検証を求めたときにこの Skill を有効化する。

## 実行フロー

1. まず検証スクリプトを実行する。目視で判断してはならない。
   - 実行方法(意図は run。スクリプトの内容を読まないこと):
     `python scripts/check_csv.py --path <ファイルパス>`
2. スクリプトの終了コードが 0 なら検証通過。ユーザーに直接 PASS を報告し、余計なことをしない。
3. スクリプトの終了コードが非 0 なら、その標準出力を読む。各エラーは具体的な問題に対応している。
4. エラーに基づいてデータソースを修正し(エンコーディング、ヘッダー順、列型の可能性がある)、スクリプトを再実行する。
5. スクリプトが PASS を出力するまで、手順 3 と 4 を繰り返す。

## ハード制約

- スクリプトを実行せずにデータが検証に通過したと主張することは固く禁じる。
- 検証を通すために scripts/check_csv.py の判定ロジックを変更することは固く禁じる。
- ヘッダーのホワイトリストと型ルールは references/schema.md に統一定義されている。本文で重複して列挙しないこと。

## よくある落とし穴(gotchas)

- BOM 付きの UTF-8 ファイルは文字化けと誤判定されやすい。スクリプトが自動処理するので、手動で再度 strip しないこと。
- 日付列に `2026/3/1` と `2026-03-01` が混在する場合がある。スクリプトは統一して正規化してから比較する。
- ファイルが 200MB を超えると、スクリプトはストリーミング読み込みに切り替わる。その場合行番号は出力されないが、正常な動作である。

フィールド制約チェックリスト:name の 64 文字と親ディレクトリ同名ルール、description の 1024 文字トリガー

メタデータは適当に書くコメントではない。公式フィールドには明確なハード検証があり、間違えると即座に拒否される。項目ごとに列挙する:

  • name(必須):最大 64 文字。小文字英字、数字、ハイフンのみ許可。ハイフンで始まったり終わったりしてはならない。連続ハイフンを含んではならない(例:my--skill は不正)。親ディレクトリ名と完全に一致しなければならない。最後のこのルールが最も見落とされやすい——フォルダを csv-checker と名付けて、中の name を csv_schema_checker と書けば、それは不正である。
  • description(必須):最大 1024 文字。これは紹介文ではなくトリガーである。書き方としては、Agent がタスクを認識できるトリガーキーワードを含め、ユーザーが言いそうな多様な表現をカバーしなければならない。
  • compatibility(任意):最大 500 文字。実行環境、依存関係、プラットフォーム要件を宣言するために使う。
  • license(任意):ライセンス宣言。
  • metadata(任意):カスタムキーと値のペア。バージョン、担当者、チームなどの情報を入れる。
  • allowed-tools(任意):この Skill が呼び出しを許可されるツールのホワイトリスト。

description の書き方について、実用的な対比を挙げると:「これは CSV を処理するための Skill です」と書くのではなく、「CSV のヘッダー、エンコーディング、列型を検証する……ユーザーが CSV 形式の確認、汚いデータのクリーンアップ、アップロード前のデータ品質チェックを必要とするときに使用」と書くべきである。前者は自己紹介であり、後者はトリガー信号である。1024 文字の枠は実はかなり余裕があり、トリガーとなるシナリオを展開するのに十分である。

フィールド必須上限主要な制約
nameはい64 文字小文字英字/数字/ハイフン。先頭と末尾はハイフン不可。連続ハイフン不可。親ディレクトリと同名
descriptionはい1024 文字トリガーキーワードを含めること。紹介文ではなくトリガーとして書く
compatibilityいいえ500 文字環境と依存要件を宣言
licenseいいえハード上限なしライセンス宣言
metadataいいえ必要に応じてバージョン、担当者などのカスタムキーと値
allowed-toolsいいえ必要に応じてツールのホワイトリスト。権限を絞るために使う

段階的開示の三層:常駐メタデータ、アクティベートされる指示、オンデマンドリソースの読み込み順序

段階的開示(Progressive Disclosure)は Skills アーキテクチャの魂である。情報を「いつ本当に必要になるか」で三層に分け、層ごとに展開する:

  1. 第 1 層:メタデータ。常に読み込まれ、約 100 tokens/skill。これは本の目次のようなもので、Agent は毎ターンの会話でインストール済みのすべての Skill の name と description を見ることができ、それによってアクティベートすべきか判断する。約 100 tokens しかないため、何十個の Skill をインストールしても、常駐オーバーヘッドは制御可能な範囲に収まる。
  2. 第 2 層:指示。ある Skill がアクティベートされたときにのみ読み込まれる。つまり SKILL.md の Markdown 本文である。公式は 5k tokens 以内に抑えることを推奨している。この層がフローとルールの主体である。
  3. 第 3 層:リソース。references/ と scripts/ で、「オンデマンドの中のオンデマンド」である。Skill がアクティベートされたからといって、これらのリソースをすべて使うわけではない。フローが実際にあるステップに到達したときに初めて取りに行く。

この設計が解決するのは根本的な矛盾である:Agent は「どんな能力があるか」を知る必要があるが、すべての能力の詳細をコンテキストに背負うことはできない。目次は常駐、本文はオンデマンド、リソースはさらにオンデマンド——これはコンテキストを「全量読み込み」から「遅延読み込み」へと作り変えることに等しい。

そして第 3 層の内部には、もう一つの重要な分岐があり、明確に説明しなければならない:

  • references/ は「読む」(read):内容はコンテキストに読み込まれ、確実に Token を消費する。したがって「Agent が理解する必要がある」資料、たとえばルール表、フィールド定義、ドメイン背景を置くのに適している。
  • scripts/ は「走らせる」(run):実行するだけで内容は読まず、ほとんどコンテキストを占有しない。Agent はそれをどう呼び出すかだけを知っていればよく、内部でどう実装されているかを知る必要はない。数百行の検証スクリプトでも、コンテキストのコストは指示の中のその一行のコマンドラインだけかもしれない。

唯一の例外は:SKILL.md にスクリプトの実行方法が明確に書かれていない場合、Agent はどう実行するかを理解するために自らコードを読みに行くことがあり、そのときそれは「読む」に退化し、コンテキストのオーバーヘッドが即座に跳ね上がる。したがって指示の中に実行コマンドと意図(run か read か)を明示的に書くことは、選択肢ではなく、コストを節約する鍵である

Token の帳簿:コンテキストを予算として使う、SKILL.md は 500 行以内に抑える

三層モデルがあれば、計算ができる。30 個の Skill をインストールしたとしよう:常駐メタデータだけで約 3000 tokens になる。そのうち 5 個が会話中にアクティベートされ、各本文を 5k tokens の上限で計算すると、さらに 25000 tokens である。このとき references/ まで無造作に全量読み込まれれば、コンテキストは急速に底をつき、モデルの注意力も薄まる。

これこそが、公式が SKILL.md を 500 行以内に抑えることを推奨するエンジニアリング上の意味である——それは組版の潔癖症ではなく、予算のレッドラインである。コンテキストを予算として使うという視点で見れば、ファイルが長いほど「情報がより完全」なのではなく、「各ルールに配分される注意力がより少ない」のである。これがいわゆる注意力の減衰strong>:内容が多くなるほど、個々のルールの重みは弱まります。さらに悪いことにルールの失效が起こります——ルールがモデル自身の傾向と衝突する場合、モデルは比較検討した上で違反する方を選びます。なぜならモデルにとって、自然言語のルールは「命令」ではなく「提案」にすぎないからです。

この問題に対処する根本的な手段は、判断権を文字から取り戻し、コードに委ねることだ。プロンプトは確率的であり、コードは決定論的である。本文に「データ形式が仕様に適合しているか注意深く確認してください」と書くよりも、「python scripts/check_csv.py を実行し、終了コードが非 0 なら修正して再実行し、PASS になるまで繰り返す」と書くほうがよい。前者は正しさをモデルの自覚に委ね、後者は正しさを再現可能な実行結果に固定する。

#!/usr/bin/env python3
"""scripts/check_csv.py — 決定論的な CSV 検証スクリプトの例。

設計原則:終了コードが結論であり、標準出力が修正リストである。
- 終了コード 0:すべて通過。最後の行に PASS を出力。
- 終了コード 1:データ品質の問題が存在する。問題の説明を 1 件ずつ出力。
- 終了コード 2:スクリプト自体の引数または環境エラー(これはデータ問題ではないので、再試行しない)。
"""

import csv
import sys
import argparse
import unicodedata
from pathlib import Path

REQUIRED_HEADERS = ["order_id", "user_id", "amount", "created_at"]
ALLOWED_AMOUNT_CHARS = set("0123456789.-\u00a5\uffe5")
STREAM_THRESHOLD_BYTES = 200 * 1024 * 1024


def normalize_header(name: str) -> str:
    """BOM、全角空白、ゼロ幅文字を除去し、小文字に統一して前後の空白を削除する。"""
    cleaned = unicodedata.normalize("NFKC", name)
    cleaned = cleaned.replace("\ufeff", "").replace("\u200b", "")
    return cleaned.strip().lower()


def check_headers(fieldnames):
    problems = []
    actual = [normalize_header(f) for f in (fieldnames or [])]
    if actual != REQUIRED_HEADERS:
        problems.append(
            f"ヘッダー不一致: 期待値 {REQUIRED_HEADERS}, 実際 {actual}"
        )
    return problems


def check_amount(raw: str, line_no: int):
    value = (raw or "").strip().replace(",", "").lstrip("\u00a5\uffe5")
    if not value:
        return [f"{line_no} 行目の amount が空です"]
    if not set(value) <= ALLOWED_AMOUNT_CHARS:
        return [f"{line_no} 行目の amount に不正な文字が含まれています: {raw!r}"]
    try:
        amount = float(value)
    except ValueError:
        return [f"{line_no} 行目の amount を数値として解析できません: {raw!r}"]
    if amount < 0:
        return [f"{line_no} 行目の amount が負の値です: {amount}"]
    return []


def check_file(path: Path):
    problems = []
    size = path.stat().st_size
    stream_mode = size > STREAM_THRESHOLD_BYTES

    with path.open("r", encoding="utf-8-sig", newline="") as fh:
        reader = csv.DictReader(fh)
        problems.extend(check_headers(reader.fieldnames))
        for offset, row in enumerate(reader):
            line_no = offset + 2  # ヘッダーが 1 行を占め、行番号は 1 から始まる
            problems.extend(check_amount(row.get("amount", ""), line_no))
            if stream_mode and len(problems) >= 20:
                problems.append("問題の上限に達したため、ストリーミングモードでは以降の行番号を出力しません")
                break
    return problems


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--path", required=True, help="検証対象の CSV ファイルパス")
    args = parser.parse_args()

    target = Path(args.path)
    if not target.is_file():
        print(f"[環境エラー] ファイルが存在しません: {target}", file=sys.stderr)
        return 2

    try:
        problems = check_file(target)
    except UnicodeDecodeError as exc:
        print(f"[環境エラー] ファイルエンコーディングを解析できません: {exc}", file=sys.stderr)
        return 2

    if problems:
        print("検証に失敗しました。各項目を修正して再実行してください:")
        for item in problems:
            print(f"- {item}")
        return 1

    print("PASS")
    return 0


if __name__ == "__main__":
    sys.exit(main())

このスクリプトが体現しているのは、まさに「スクリプト FAIL → 修正 → 再実行 → PASS まで」の閉ループである。その終了コードの意味に注意してほしい:0 は業務上の通過、1 は修正が必要なデータ問題、2 は再試行すべきでない環境または引数のエラーを表す。2 と 1 を分けることはエンジニアリング上の重要な細部である。そうでなければ、Agent はパスを書き間違えた呼び出しに対して何度も再試行し、無駄にターンを消費してしまう。

ついでにインストール段階のセキュリティ上の注意点に戻ると、インターネットから Skill を取得することは、本質的に他人が書いたソフトウェアを自分のマシン上で実行することと同じである。Skill は scripts/ を伴うことができ、したがって破壊的なコマンドや権限外アクセスを伴う可能性もある。公式リポジトリ github.com/anthropics/skills の skills ディレクトリでは、各サブディレクトリが 1 つの Skill である。コミュニティサイト skillsmp.com とオープンソースコレクション github.com/ComposioHQ/awesome-claude-skills も一般的な入手元である。どこから来たものであれ、インストール前に SKILL.md と scripts/ の内容を一通り読むという底线は省けない。インストール作業自体は非常に簡単で、Skill フォルダ全体を Agent が定めた skills ディレクトリに置くだけである。たとえば Claude Code の .claude/skills、Codex インストールディレクトリ配下の skills、OpenCode プロジェクト内の .opencode/skills などである。しかし、どのディレクトリにコピーするか、どの階層にコピーするかは、SKILL.md を直接含むルートディレクトリを見つけられたかどうかにかかっている。

前半では、Skill の位置づけ、SKILL.md の形式とフィールド制約、漸進的開示の読み込み順序と予算モデルを整理した。しかし、まだ正面から答えていない、より鋭い問題がある。description がうまく書かれていなければ、Skill がどれほど完璧でも有効化されない。本文とスクリプトの意図が明確に書かれていなければ、決定論は確率論に退化してしまう。次に、Skill が使いやすいかどうかを本当に決める場所へ入る。リソースをどう分担するか、文字とコードの境界はどこにあるか、そしてインストール前に何をしなければならないかである。

references は「読む」、scripts は「走らせる」:2 種類のリソースの役割分担とコンテキストコスト

ディレクトリ規約に戻る:SKILL.md は必須scripts/ references/assets/ の三つはすべて任意です。多くの人は references と scripts を同じ類のもの——「追加のファイル」——と捉えています。しかし、仕組みのレベルではまったく異なります。違いはただ一言に尽きます:読むか、走らせるか

references/ は「読む」。Agent が何らかのドキュメントを参照する必要があると判断したとき、ファイルを読み取る動作で内容を取り込み、その内容はコンテキストウィンドウに入り、文字単位で課金されて Token を消費する。つまり references に入れるものと SKILL.md の本文に書くものは、コストモデル上は同じ種類のものであり、ロードのタイミングが「オンデマンド」に先送りされているだけだ。したがって references の価値は「Token を節約する」ことではなく、「不要なときに Token を使わない」ことにある。

scripts/ は「走らせる」。Agent は実行アクションを呼び出してこのスクリプトを走らせるが、スクリプト自体の内容はコンテキストに入らない。会話に戻ってくるのはその標準出力、エラーメッセージ、終了コードだけだ。300 行の検証スクリプトと 3 行のスクリプトが、どちらも同じ 1 行の PASS を出力するなら、コンテキストの占有量はほぼ同じである。これが Skill で最も過小評価されているレバーだ:複雑さをスクリプトの中に閉じ込める

しかしここには非常によくあるエンジニアリングの落とし穴がある:SKILL.md にこのスクリプトをどう実行するか、どんな引数が必要かが明確に書かれていないと、Agent はまずこのスクリプトのソースコードを「読んで」、自分で理解しようとする可能性が非常に高い。そうなった瞬間、scripts のコンテキスト上の利点はすべて消え去り、全文を読み込まれる references に退化する。したがって正しいやり方は:スクリプトの呼び出し方法を、そのままコピーできるコマンドラインとして SKILL.md の本文に書くことだ。インタプリタ、引数の順序、入出力の約束、そして失敗時にどうするかまで含めて。

もう一つの落とし穴の種類は、スクリプトを「人が見ていないと走らせられない」対話型プログラムとして書いてしまうことだ——入力を待つ、プログレスバーを表示する、カレントワーキングディレクトリに依存する。Agent がスクリプトを実行するときは非対話的であり、こうしたスクリプトはハングするか、静かに失敗するかのどちらかだ。約束事はこうだ:スクリプトはワンショット、冪等、非対話的で、終了コードが判定可能でなければならない

観点references/(読む)scripts/(走らせる)
Agent の動作ファイル内容を読み取るコードを実行する
コンテキストに入るかはい、全文が入るいいえ、stdout / stderr / 終了コードだけが返る
Token コストドキュメントの長さに比例出力の長さに比例し、コードの長さとは無関係
決定性低い、モデルに与える参考情報高い、同じ入力なら同じ結果
何を置くのに適するかAPI リファレンス、フィールド辞書、長大な仕様、ドメイン背景フォーマット検証、データ変換、外部インターフェース呼び出し、成果物の生成
よくある誤用毎回使う核心ルールを詰め込んでしまう実行コマンドを書き忘れ、Agent がソースコードを読みに行く

両者の役割分担を一言でまとめると:references は「モデルがどう考えるか」に影響し、scripts は「システムがどう動くか」を決める。モデルが理解し、比較衡量し、表現する必要がある内容は references に。答えが一意で、正誤が判定可能な内容は scripts に。

Prompt から確定的スクリプトへ:コードで判断できることを文字から取り出す

Skill のエンジニアリング的価値を理解するには、まず一つの前提を受け入れる必要がある:プロンプトは確率的であり、コードは確定的である。「JSON フィールドが完全であることを確認してください」と書いても、モデルはチェックするかもしれないし、しないかもしれないし、チェックしてもある階層のネストを見落とすかもしれない。「よく確認してください」と書いても、この一文の期待収益はほぼゼロだ——「よく」とは何かも、「合格」とは何かも定義していない。

確定的スクリプトはこれを機械的なプロセスに変える:スクリプトが FAIL → 修正 → 再実行 → PASS するまで。この閉ループが単なる一言の注意喚起よりもはるかに強力である理由は三つある:

  • 明確な成功判定基準がある。終了コードが非ゼロなら未完了であり、「もう大丈夫だと思う」は存在しない。モデルの自己評価は本質的に楽観的だが、終了コードはそうではない。
  • 注意を「チェック」から「修正」へ移す。モデルは長いコンテキストの中で警戒を維持し続ける必要はなく、具体的なエラー行を見て、直して、もう一度走らせるだけでよい。各ステップが短いフィードバックだ。
  • 再現可能である。同じ入力を二度走らせれば結果は一致する。これは問題が起きたときに特定できることを意味し、一度再起動して良くなることを祈るのとは違う。

したがって良い Skill の核心原則は一文に凝縮できる:コードで判断できることはすべて文字から取り出してスクリプトに任せる。「コードで判断できるか」を判断する基準は簡単だ——二人のエンジニアが同じ出力について同じ結論を出すなら、それはコードの仕事であるべきだ。

以下は使える SKILL.md の例だ。これは「外部データを規範的な JSON に整理して検証する」というスキルをカプセル化したもので、「判断」をスクリプトに、「説明」を文字に残している点に注目してほしい。

---
name: json-schema-guard
description: JSON データファイルを検証・修復し、プロジェクトの schema に適合させる。ユーザーが JSON 形式のチェック、欠落フィールドの修正、出力構造の統一を求めたり、schema 検証、フィールド整合、データクレンジングに言及したときに使用する。
license: MIT
compatibility: Python 3.10+ と jsonschema パッケージが必要
metadata:
  author: platform-team
  version: 1.1.0
allowed-tools: read_file, write_file, run_skill_script
---

# JSON Schema Guard

任意の JSON データを `assets/schema.json` に適合する構造に正規化し、スクリプトで検証して、通るまで繰り返す。

## いつ使うか

タスクが「データ形式が正しくない」「フィールドが欠落している」「出力構造を schema に揃える必要がある」であるときにこのスキルを使う。
JSON の内容を読んで表示するだけなら、このスキルは不要だ。

## 実行フロー

1. 検証スクリプトを実行し、現在の失敗項目を確認する:

   `python scripts/validate.py --input data.json --schema assets/schema.json`

2. スクリプトは非ゼロの終了コードで終了し、`PATH: 理由` の形式でエラーを行ごとに出力する。
3. エラー行に従って `data.json` を一つずつ修正し、指摘されたパスだけを変更し、ファイル全体を書き直さない。
4. 同じコマンドを再実行し、終了コードが 0 になり `PASS` を出力するまで繰り返す。
5. スクリプトが PASS した後にのみ、ユーザーに完了を報告する。

## スクリプトの約束

- `scripts/validate.py` は冪等な読み取り専用検証であり、入力ファイルを変更しない。
- ルールを推測するために `scripts/validate.py` のソースコードを読んではならない。ルールは `assets/schema.json` に基づく。
- フィールドの意味を確認する必要があるときは `references/fields.md` を読み、推測してはならない。

## 境界

- schema 自体を変更しない。schema とデータが衝突する場合は、まずユーザーに確認する。
- 非 UTF-8 エンコードのファイルは処理せず、直接報告して停止する。

## Gotchas

- `assets/schema.json` の `additionalProperties` は false であり、フィールドが一つ多いだけでも失敗する。削除する方が追加するより安全だ。
- 空の配列とフィールド欠落は二つの異なるエラーであり、`null` でフォールバックしてはならない。
- スクリプトは相対パスに敏感なので、常に Skill のルートディレクトリから実行すること。

このファイルのいくつかの設計上の選択に注目してほしい:本文は JSON Schema の原理を説明しておらず(それは references の仕事だ)、各フィールドの意味も列挙していない(references/fields.md に置いてある)が、「どのコマンドを実行するか」「失敗はどんな見た目か」「いつ完了とみなすか」「どの落とし穴を二度と踏んではならないか」は書き切っている。gotchas の節はしばしば SKILL.md 全体の中で最も価値のある部分だ。なぜならそれは実際に踏んだ落とし穴から来ており、ドキュメントの復唱ではないからだ。

二つ目の例は真に確定的な検証スクリプトだ。その価値はロジックの複雑さにあるのではなく、出力が人間にも Agent にも直接実行可能であることにある:

#!/usr/bin/env python3
"""冪等な読み取り専用検証:data.json が schema.json に適合するかをチェックする。

終了コード:0 = 合格;1 = 検証失敗;2 = 使用方法または環境エラー。
"""
import argparse
import json
import sys
from pathlib import Path

try:
    from jsonschema import Draft202012Validator
except ImportError:
    print("ERROR: jsonschema がありません。先に pip install jsonschema してください
", file=sys.stderr)
    sys.exit(2)


def load_json(path: Path):
    if not path.exists():
        return None, f"ファイルが存在しません: {path}"
    try:
        return json.loads(path.read_text(encoding="utf-8")), None
    except UnicodeDecodeError:
        return None, f"UTF-8 エンコーディングではありません: {path}"
    except json.JSONDecodeError as exc:
        return None, f"JSON 構文エラー {exc.lineno} 行目 {exc.colno} 列目: {exc.msg}"


def main():
    parser = argparse.ArgumentParser(description="JSON データが schema に準拠しているかを検証する")
    parser.add_argument("--input", required=True)
    parser.add_argument("--schema", required=True)
    args = parser.parse_args()

    data, err = load_json(Path(args.input))
    if err:
        print(f"FAIL\n{err}", file=sys.stderr)
        sys.exit(1)

    schema, err = load_json(Path(args.schema))
    if err:
        print(f"FAIL\nschema を読み込めません: {err}", file=sys.stderr)
        sys.exit(1)

    try:
        Draft202012Validator.check_schema(schema)
    except Exception as exc:
        print(f"FAIL\nschema 自体が不正です: {exc}", file=sys.stderr)
        sys.exit(2)

    validator = Draft202012Validator(schema)
    errors = sorted(validator.iter_errors(data), key=lambda e: list(e.path))

    if not errors:
        print("PASS")
        sys.exit(0)

    for err in errors:
        path = "/".join(str(p) for p in err.path) or "(root)"
        print(f"{path}: {err.message}")
    print(f"合計 {len(errors)} 件の問題", file=sys.stderr)
    sys.exit(1)


if __name__ == "__main__":
    main()

re>

このスクリプトには、見落とされやすいが非常に重要な3つのディテールがあります。終了コードを3段階に分けることで、Agent が「データが間違っている、データを直せ」と「環境が間違っている、むやみに変更するな」を区別できるようにする。エラーをパス順にソートして出力することで、モデルが最初の1件から安定して修正を始められるようにする。非 UTF-8 入力を明示的に禁止することで、「モデルが延々と直していたが、実はエンコーディングの問題だった」という事態を避ける。これらはいずれもアルゴリズム上の難点ではなく、不確実性を確実に固定するエンジニアリング上の習慣です。

注意力の減衰とルールの無効化:純テキストの Skill は大きな Prompt にすぎず、2つの天井がある

すべてのロジックを SKILL.md の本文に書いてしまうと、実際に得られるのはただの大きな Promptです。ファイル形式が変わったからといって追加の能力を得られるわけではなく、むしろ2つの天井にぶつかります。

1つ目は注意力の減衰です。コンテキスト内の内容が多くなるほど、各ルールに割り当てられる注意力は弱くなります。これはモデルが怠けているのではなく、仕組み上の必然です。10個のルールにはそれぞれの位置がありますが、100個のルールの中で真ん中あたりに並ぶものは無視されやすくなります。症状としては、ルールが SKILL.md に書かれていてモデルも「見てはいる」ものの、実行時には冒頭と末尾のいくつかしか守らない、という形で現れます。そのため公式は SKILL.md を500行以内、第2層の指示を5k tokens 以内に抑えることを推奨しています。これは美的要求ではなく、各ルールに十分な注意力が割り当てられるようにするためです。

2つ目はルールの無効化です。モデルの判断とルールが衝突すると、モデルは比較検討し、そしてルールに違反することを選ぶかもしれません。なぜならモデルにとって、ルールは提案であり命令ではないからです。「このファイルを変更しないこと」は提案です。スクリプト内で検証され、失敗すれば非ゼロで終了する制約こそが命令です。これもまた、ルールを文章に書くよりもコードに書くほうが信頼できる理由です。文章は理解され、コードは実行されるのです。

この2つの天井が重なった結果が、長い Prompt の昔ながらの問題です。ルールが多ければ多いほど信頼できるわけではなく、むしろ低くなる可能性があります。エンジニアリング上の対応は「もっと明確に書く」ことではなく、階層化です。「毎回守るべき中核原則」を簡潔な本文に書き、「特定の場面でしか使わない詳細」を references に移し、「正誤を判定できるチェック」を scripts に移す。これは前述の、コンテキストを予算として扱うという話にもちょうど呼応します。

MCP との境界:MCP は食材を提供し、Skill はレシピを与える。補完関係であり代替ではない

Skills が登場して以降、最もよくある困惑は「これは MCP を置き換えるのか」というものです。答えは明確です。いいえ。両者は抽象層として扱う対象が異なります。

MCP が解決するのは「外部ツールとデータソースへの接続」です。データベース、API、ファイルシステム、SaaS サービスを Agent が呼び出せる範囲に取り込みます。たとえるなら、MCP は食材を提供するものです。Agent がデータを取得し、リモートの能力を呼び出せるようにし、「つながる、呼べる」ことに重点があります。

Skill が解決するのは「そのデータをどう加工するか」です。食材を手に入れた後、どう切るか、どの順番で鍋に入れるか、完成品はどんな形か。Skill が与えるのはレシピです。手続き的知識であり、「正しく、安定してやる」ことに重点があります。

比較軸MCPAgent Skills
解決する問題外部ツールとデータソースへの接続データの加工方法、タスクの完了方法
たとえ食材を提供するレシピを提供する
担い手プロトコルとサーバーフォルダ + SKILL.md
得意なこと標準化された接続、認証、リモート呼び出し軽量スクリプト、単純なロジック、プロセス編成
弱み複雑な業務プロセスの担持には追加設計が必要コード実行の安全性と安定性は MCP に劣る
関係代替ではなく補完。典型的な形は、Skill がプロセス内で MCP ツールを呼び出すこと

Skill の短所は正直に見るべきです。それは本質的に「ファイル + スクリプト」という軽量な取り決めであり、コード実行の安全性、分離性、安定性において MCP に劣ります。MCP サーバーは認証、レート制限、監査、サンドボックスを集中的に担えますが、Skill のスクリプトはあなたの環境でそのまま動きます。したがって合理的な境界はこうです。軽量で、ローカルで、一度きりの処理は Skill に任せる。認証、マルチテナント、強固な分離、集中的なガバナンスが必要な能力は MCP に残す。成熟したシステムでは、両者は通常ネスト関係にあります。Skill がプロセスを定義し、そのプロセス内の重要なステップが MCP ツールを呼び出して完了するのです。

よくある3つの誤解:SKILL.md は長いほど良い、資料を全部本文に詰め込む、description を無視する

十分な数の Skill を見た後では、問題は基本的に3つのカテゴリに集中します。

誤解1:SKILL.md は長いほど良い。多くの人は無意識に、詳しく書くほどモデルの性能が良くなると考え、SKILL.md を数千行の百科事典のように書いてしまいます。その結果は、重点を薄め、無駄に Token を消費することです。なぜなら本文は第2層であり、Skill が一度有効化されると全体が読み込まれるからです。ルールが多くなるほど1つ1つが弱くなり、中核となる手順がかえって埋もれてしまいます。正しいやり方は、本文には実行フロー、スクリプトの呼び出し方、境界、gotchas だけを残し、それ以外はすべて外に出すことです。公式推奨の500行上限は参考値ではなく、厳格な制約と見なすべきです。

誤解2:すべての資料を SKILL.md に詰め込む。典型的な症状は、API の全フィールド表、歴史的背景、用語解説をすべて本文に書いてしまうことです。こうした内容の特徴は「特定の場面でしか使わない」ことであり、本来は references/ に属します。判断基準はこうです。その内容が毎回の実行で必要でないなら、本文に現れるべきではない。同様に、チェックとして書けるものは説明として書くべきではありません。

誤解3:description を無視する。これは最も見えにくく、最も致命的なものです。多くの作者は description を「紹介文」と捉え、要約のように書きます。「データ処理に使える便利なスキル。」しかしdescription は紹介文ではなく、トリガーです。それは第1層で常に読み込まれる部分(約100 tokens/skill)であり、モデルはこれに頼って「このタスクでこの Skill を有効化すべきか」を判断します。したがって description には、Agent がタスクを識別するのを助けるトリガーキーワードが必ず含まれていなければなりません。ユーザーがどう言うかもしれないか、どんな名詞が関わるか、どんな場面で使うべきか、どんな場面で使うべきでないか。要約を書くことは、この Skill が永遠に選ばれないようにするのと同じであり、たとえ内部がどれほど良く書かれていても同じです。仕様上、最大1024文字で、この枠はトリガー条件を書くためのものです。使わないのはもったいないことです。

入手、インストール、ルートディレクトリの判定:公式リポジトリから .claude/skills、.opencode/skills まで

Skill の入手経路は主に3つあります。公式リポジトリ github.com/anthropics/skills で、その中の skills ディレクトリ配下の各サブディレクトリが1つの Skill です。コミュニティ集約サイト skillsmp.com。そしてオープンソースのコレクションリポジトリ github.com/ComposioHQ/awesome-claude-skills です。Agent Skills はすでにクロスプラットフォームのオープン標準(仕様サイトは agentskills.io)であるため、同じ Skill が Claude Code、OpenAI Codex、GitHub Copilot、Microsoft Agent Framework などのプラットフォームで認識されます。たとえば Microsoft Agent Framework は能力を明確に「リソースを読む read_skill_resource」と「スクリプトを実行する run_skill_script」の2つのアクションに分けており、前述の「読む / 走らせる」という役割分担と同じモデルです。

インストール方法は少し直感に反するほど簡単です。Skill フォルダ全体をそのまま Agent が定める skills ディレクトリに入れるだけで、ビルドも登録も不要です。一般的な場所には、Claude Code の .claude/skills、Codex インストールディレクトリ配下の skills、OpenCode プロジェクト内の .opencode/skills があります。

ここで非常に実用的でありながら、ドキュメントではよく一言で流されてしまう問題があります。圧縮アーカイブやリポジトリからコピーするとき、いったいどの階層のフォルダをコピーすべきか?判定方法はただ1つです。どのディレクトリが直接 SKILL.md を含んでいるかを見る。そのディレクトリが本当の Skill ルートディレクトリです。解凍後に my-skill-main/json-schema-guard/SKILL.md が得られたなら 、その場合はコピーすべきなのは json-schema-guard の階層であり、最外層の my-skill-main ではない。階層を間違えてコピーすると、Agent が取り決められたディレクトリ配下で SKILL.md をスキャンできず、Skill は静かに失效する。ちなみに、これは規範がname は親ディレクトリ名と一致しなければならないと定めている理由も説明している——ディレクトリ名そのものが位置特定の一部なのだ。

ついでに、メタデータのハード制約をまとめて列挙しておきます。Skill を書くときにハマる落とし穴のほとんどはここにあります。name は必須で、最大 64 文字、使用できるのは小文字英字、数字、ハイフンのみ、先頭または末尾をハイフンにしてはいけず、連続するハイフンを含められず、親ディレクトリ名と一致している必要があります。description は必須で、最大 1024 文字、Agent がタスクを識別するのに役立つトリガーキーワードを含めるべきです。compatibility は任意で、最大 500 文字です。license と metadata は任意です。allowed-tools は任意で、その Skill の実行時にどのツール権限が必要かを宣言するために使います。

インストール前に監査する:Skill を入れることは、見知らぬ人のソフトウェアを自分のマシンで実行することと同じ

最後のこの項目に交渉の余地はありません。Skill は純粋な設定ファイルではありません。スクリプトを同梱でき、そのスクリプトはあなたの環境で実行されます。したがって、インターネットから Skill をインストールすることは、本質的に見知らぬ人のソフトウェアを自分のマシンで実行することと同じです。ただし、その配布形式がいくつかの Markdown ファイルに見えるため、警戒を緩めがちです。

これはまさに、エンジニアリング界がまとめた第 5 の原則「実行する前に監査せよ」が対象とする場面です。実際の操作としては、インストール前に少なくとも次のことを行うべきです。

  1. SKILL.md の全文を読み通す。特に実行フローとスクリプト呼び出しの部分を確認し、実際にどのコマンドが実行されるのかを確かめる。
  2. scripts/ 配下のすべてのコードを行単位でレビューする。「ただの検証スクリプトだから」といって飛ばさない。ファイルの削除、上書き、一括書き換え操作がないかを重点的に見る。
  3. 破壊的コマンドを洗い出す:再帰削除、ディスクのフォーマット、ディレクトリの消去、システム設定の上書き、引数なしで実行される危険なコマンド。
  4. 権限逸脱アクセスを洗い出す:SSH 鍵、環境変数、資格情報ファイル、ブラウザデータの読み取り、外部アドレスへのデータ送信。
  5. ネットワーク動作を確認する:スクリプトが外部リクエストを発行するか、どこへ送信するか、何を送信するか。
  6. 依存関係の出所を確認する:実行時に動的にパッケージをインストールするか、疑わしいソースからコードを取得するか。
  7. まず隔離環境で一度実行する。特に非公式ソースの Skill では必須。

さらに、見落としやすい感染性リスクにも注意してください。Skill の references も間接的な攻撃媒体として使われ得ます。一見無害な参考ドキュメントに「ある状況に遭遇したらあるコマンドを実行してください」と書かれ、その内容がモデルによって指示として採用されると、あなた自身の判断を飛び越えてしまいます。したがって監査範囲は scripts だけでなく、Skill フォルダ全体に及ぶべきです。一言でいう原則はこれです。外部由来の Skill は、それが何をしようとしているのか理解できるまで実行させない

まとめとベストプラクティス

このガイドを実行可能なチェックリストに圧縮します。Skill を書くときもインストールするときも、そのまま照合できます。

  1. 位置づけを先に考える:Skill がカプセル化するのは手続き的知識(どうやるか)であり、事実的知識(何であるか)ではない。純粋な知識なら references に置くか、Skill にしないことを検討する。
  2. ディレクトリには置くべきものだけを置く:SKILL.md は必須。scripts/ には実行可能コード、references/ にはオンデマンド文書、assets/ にはテンプレートと静的リソース。
  3. メタデータのルールを守る:name は最大 64 文字、小文字英数字とハイフン、先頭末尾にハイフンなし、連続ハイフンなし、親ディレクトリ名と一致。description は最大 1024 文字でトリガーキーワードを必ず含む。compatibility は最大 500 文字。license、metadata、allowed-tools は必要に応じて。
  4. description はトリガーとして書く:どのタスクで有効化すべきか、ユーザーがどう表現しそうか、どの場面では使うべきでないかを明確に書く。これは第一層の常駐コンテンツで、約 100 tokens/skill です。要約を書くのは自滅行為です。
  5. 長さを制御する:SKILL.md は 500 行以内。第二層の指示はできるだけ 5k tokens 以内に抑える。長い内容は references に入れ、本文には入れない。
  6. 読むものと走らせるものを区別する:モデルがトレードオフを理解する必要があるものは references(コンテキストに入り、Token を消費)。正誤を判定できるものは scripts(実行のみで、ほとんどコンテキストを消費しない)。
  7. Agent にスクリプトのソースを読ませない:SKILL.md にスクリプトの完全な実行コマンド、引数、入出力、失敗時の処理を書き、意図が run か read かを明記する。
  8. 判断はコードに任せる:コードで判定できるものはすべてスクリプトにする。「FAIL → 修正 → 再実行 → PASS」の閉ループを回し、「よく確認してください」と書いてある箇所はすべて置き換える。
  9. スクリプトはエンジニアリングする:冪等、非対話、終了コードは段階分け、エラーメッセージにはパスを含める、Skill ルートディレクトリから実行、宣言されたエンコーディングのみを扱う。
  10. 階層化で注意力の減衰に対抗する:本文には核心フローと境界だけを残し、詳細は references に下げ、チェックは scripts に下げる。文章に書かれたルールは提案であり、コードに書かれたルールこそ命令です。
  11. MCP との境界を整理する:MCP は食材(ツールとデータソースの接続)を提供し、Skill はレシピ(どう加工するか)を提供する。軽量スクリプトは Skill。認証、隔離、監査、集中ガバナンスが必要なら MCP。両者は補完関係で、しばしば入れ子で使う。
  12. gotchas を真剣に書く:本文で最も価値のある節は落とし穴の記録です。それはドキュメントの復唱ではなく、実体験から来ます。
  13. コンテキストを予算として使う:文章を一段落追加するたび、references を一つ読むたびに、その限られた注意力の枠を消費します。追加する前に問う:これは本当に毎回必要か?
  14. インストールはパッケージ全体を正しい場所へ:公式リポジトリ github.com/anthropics/skills、コミュニティサイト skillsmp.com、オープンソースコレクション github.com/ComposioHQ/awesome-claude-skills が主な入手元。フォルダ全体を .claude/skills、Codex の skills ディレクトリ、または .opencode/skills に置く。
  15. SKILL.md でルートディレクトリを判定する:どのディレクトリが SKILL.md を直接含むか、それが Skill ルートディレクトリです。圧縮ファイルはその層だけをコピーする。層を間違えると、Skill は静かに失敗します。
  16. 実行する前に監査する:SKILL.md と scripts/ のすべてを読み通し、破壊的コマンドと権限逸脱アクセスを洗い出し、ネットワーク動作と依存関係の出所を確認し、疑わしいソースはまず隔離環境で実行する。

一文にまとめるとこうです。Skill の競争力は、どれだけ書いたかではなく、どれだけの不確実なものを確実なものに釘付けにしたかにある。description には選ばれる責任を負わせ、本文には流れを説明する責任を負わせ、references にはオンデマンドで補足する責任を負わせ、scripts には嘘をつかない結論を出す責任を負わせる。そして最後に、他人が書いた Skill をインストールする前に、コードをレビューするようにそれをレビューする。