SKILL.md を作成する際に実際に記述すべき内容(15 分読了)
この記事は、SKILL.md ファイルが単なるドキュメントではなく、LLM の学習プロセスや推論能力を最適化するための構造化された「指示書」であることを解説し、その実装方法と効果を詳述している。
キーポイント
SKILL.md の本質的な役割
SKILL.md はプロジェクトの静的な説明ではなく、AI エージェントや LLM がタスクを遂行するために必要な「スキルセット」と「思考プロセス」を定義する動的な指示書として機能する。
構造化された学習データの提供
コードの書き方、エラー処理のロジック、ベストプラクティスなどを明確に記述することで、AI がコンテキストを理解し、一貫性のある高品質なコード生成を可能にする。
実用的なテンプレートと構成
プロジェクトの目的、使用技術スタック、開発者の好み、そして具体的なタスク実行手順を含む標準的な構成例を示し、即座に活用可能な形式を提供している。
影響分析・編集コメントを表示
影響分析
この記事は、LLM を活用したソフトウェア開発における「プロンプトエンジニアリング」の概念を、構造化ドキュメントという形で具体化した点で重要です。開発者が AI にプロジェクトの文脈やスタイルを効率的に伝達するための標準的なプラクティスとして定着する可能性があり、AI 支援コーディングの生産性向上に直結する実践的な知見を提供しています。
編集コメント
「ドキュメント」という従来の概念を、AI との対話における「学習データ」として再定義した視点は非常に示唆に富んでいます。開発現場での AI 活用効率化のために、即座に導入を検討すべきプラクティスです。
スキルとは小さなプログラムのことです。
それには3 つの実行ステージがあります:1 つ目はターンごとに読み込まれるもの、2 つ目は呼び出し時に読み込まれるもの、そして 3 つ目は必要に応じて読み込まれるものです。スキルがプログラムである以上、典型的なソフトウェアの劣化(環境の drifting、バージョン依存性、静かで再現不可能な失敗)に悩まされることになります。
これらの失敗は特定の形で現れます。エージェントが何らかの作業を行う前に、コンテキストウィンドウの 20% を無言のうちに使ってしまうスキル。チームメイトと共有して誤ったディレクトリでビルドを実行するまで完璧に動作していたスキル。あるモデル向けに慎重に調整されたスキルが、より優れたモデルへアップグレードした瞬間に出力が悪化してしまうケースです。
これらは個別のバグではありません。同じ誤解の4 つの顔に過ぎません:ローダー仕様をプロンプトとして扱っているという誤解です。
この投稿では、スキルの本質的な仕組みと、ランタイムを理解することが表面でのあらゆる行動をどう変えるのかについて解説します。
スコープに関する注記。スキルはもはや Claude 専用の機能ではありません。Anthropic は2025年12月に SKILL.md フォーマットをオープン標準として公開し(agentskills.io)、同じファイルが now Claude Code、Kiro、Cursor、Codex CLI など across で動作するようになりました。この投稿で示すメンタルモデルはこれらすべてに適用されます。ここでは読み取りを行うエージェントハッチとして *Claude* を略称として使用しますが、ご自身のランタイムに置き換えてお読みください。
私が初めてスキルを書いたとき、それはエージェントが参照する長いプロンプトだと考えていました。
私は一度、非常に大きな SKILL.md を作成しました。おそらく 1,200 行ほどです。上部にはワークフローを記し、コードベース内のすべてのモジュールのマップ、サンプルコード、サービス間のメッセージ契約(message contracts)、フレームワーク固有のパターン、そして下部には私が知っていたあらゆる落とし穴のリストを記載しました。これは機能しましたが、エージェントが実際の作業を行う前にコンテキストウィンドウの約 20% を消費してしまいました。
私はそれを書き直しました。同じ指示、同じ出力ですが、異なるアーキテクチャを採用しました:3 つのリファレンスファイルと 1 つのヘルパースクリプトを参照する、180 行の SKILL.md です。新しいバージョンのコストは 7% でした。
指示自体は変わりません。変わっていたのはアーキテクチャです。その 3 倍の違いが生じた場所こそが、私が実際には長いプロンプト(prompt)を書いていたわけではないという最初の兆候でした。
プロンプトとは静的なテキストのことです。作成して出荷し、モデルは各ターンでそれをすべて読みます。スキルはそうは動きません。スキルは*ローダー仕様*(loader specification)なのです。あなたは、コンテキストに何を、いつ、どのコストで含めるべきかを記述しているのです。テキスト自体も重要ですが、構造こそが、モデルの作業メモリへの転送過程で生き残るものを決定します。
この再定義こそが本稿の核心です。他のすべてはここから派生するものです。
*実際のスキールの再構築。同じタスク、同じモデル、同じ出力。3 倍の違いが生じたのは、指示の内容ではなく、その指示がどこに配置されていたかによるものです。
スキルは、Anthropic が*段階的開示*(progressive disclosure)と呼ぶ原則に基づいて動作します。公式ドキュメントではこれを明確に定義しています:
スキルには 3 つ種類のコンテンツを含めることができ、それぞれ異なるタイミングで読み込まれます。
これが、同じ指示を持つ 2 つのスキルが全く異なる挙動を示す理由です。あるスキルは必要な時にのみ 180 行を読み込みますが、別のスキルはターンごとに 1,200 行をすべて出力してしまいます。
Anthropic はこれらのレベルを、コンテキストウィンドウ(context window)を保護するために構築しました。もしスキルがすべての情報を先読み(front-loading)してしまうと、会話履歴やツール出力の領域を圧迫してしまいます。段階的な開示(progressive disclosure)を採用することで、「万一に備えた」指示に対してコストを支払うのを防ぎ、「必要な時に実行する」ことだけにコストを集中させることができます。
*各レベルは異なるタイミングで読み込まれ、異なるコストがかかります。多くの著者はすべての内容を Level 2 に配置しています。*
Level 1: メタデータ。YAML frontmatterから取得される名前と説明です。すべてのターンで常に読み込まれます。公式ドキュメントでは、インストールされたスキルあたり約 100 トークン程度とされています。エージェントはこの説明を使って、そのスキルが関連性があるかどうかを判断します。これは使用の可否ではなく、ルーティング(経路選択)の決定です。このレベルを正しく設定することが最も重要です。もし説明が間違っていれば、他の内容はすべて無意味になります。
Level 2: SKILL.md の本文。手続き的な指示です。エージェントがスキルが適用されると判断した際にのみ読み込まれ、bash を介してファイルを読み込むことで実行されます。Anthropic のベストプラクティスドキュメントでは、推奨される上限を 500 行としています。ここが、多くの人が不要なコンテンツを追加してしまう場所です。
レベル3:参照とスクリプト。 SKILL.md から参照されるバンドルファイルです。参照は、本文がそれらを指す場合にのみエージェントが読み取るマークダウン形式です。スクリプトはエージェントが*実行する*実行可能コードであり、出力はコンテキストに入り込みますが、ソースコード自体は入りません。実質的に無制限です。
Anthropic のエンジニアリングチーム(Barry Zhang 氏、Keith Lazuka 氏、Mahesh Murag 氏)は、2025 年 10 月の発表で次のように説明しています:*「目次から始まり、特定の章があり、最後に詳細な付録が続く、よく整理されたマニュアルのようなものです。スキルを使えば、Claude は必要な時だけ情報をロードできます」。
アーキテクチャを正しく設計すれば、その価値が認められるまでスキルのコストはほぼゼロです。間違えた場合、毎回支払いが発生します。
夕食時の厨房を想像してください。
*シェフの注意力は希少なリソースです。エージェントのコンテキストウィンドウと同じです。
壁にはレシピのタイトルと一行の要約が書かれた掲示板があります。「パスタ・カルボナーラ:イタリアのクラシック、ゲストがベーコン入りのクリーミーなパスタを望む時に使用」*。シェフは絶えずそれをちらりと見ます。それは周辺視野に収まるほど小さいです。これがフロントマター(前書き情報)です。
注文が入ると、シェフは対応するカードを選び、完全なレシピを引き下ろします。材料、手順、技術的な注釈などです。そのレシピは壁にはありません。サービス中にスクロールするには clutter すぎ、気が散りすぎて、スキャンしきれないからです。必要になった時だけ引き下ろされます。これが SKILL.md です。
レシピには時々「ソースについては、47 ページのソース参照を参照してください」と書かれています。シェフはバインダーに向かって 47 ページを開き、そのページだけを読み、バインダー全体を読むわけではありません。これが references/ です。
隅にはスタンドミキサーがあります。レシピには「3 分間ミキサーを使用する」とあります。シェフはミキサーの回路図を読んだりしません。シェフは材料を渡し、ボタンを押して出力を得ます。これが scripts/ です。
この比喩は圧力下でも成り立ちますが、それが比喩に対する唯一のテストです。私が自分のスキルで遭遇したすべての失敗モードは、この「キッチン」のルールに違反することに遡ります。
ワークフローを SKILL.md へ移行し始めたばかりの頃、私はランタイムを「自分で考えて解決できる」賢いインターンだと扱っていました。
それは間違いでした。なぜならスキルランタイムは決定論的なローダーだからです。YAML の一行をどこに置くかといった些細なアーキテクチャ上の選択が、エージェントの推論を静かに壊す可能性があります。これらは単なるバグではなく、アンチパターンです。以下に挙げるそれぞれは、「キッチン」のロジックに違反し、コンテキストのドリフト、高いレイテンシ、あるいは幻覚的な出力という代償を支払った瞬間を表しています。
私が最初に間違えたのは、段階的開示(progressive disclosure)が存在することを理解する前でした。
SKILL.md にそれがあったので、参照ファイルに YAML フロントマターを追加しました。参照は重要でメタデータを必要だと感じたからです。私はフロントマターが実際に何をするのかを理解していませんでした。
フロントマターは、起動時にシステムプロンプトに読み込まれるものです。フロントマターを含むすべてのファイルは、常時読み込まれるセットに対してその名前と説明を追加します。ピンボードです。参照ファイルにフロントマターを追加すると、それがトップレベルのスキルであるかのように壁にピン留めされます。しかし実際にはそうではありません。今やピンボードには 5 つではなく 50 のエントリが表示されており、そのほとんどはルーティング時に可視化されるはずではなかったサブページです。
実際の運用では、エージェントが親スキルの代わりに参照ファイルを直接トリガーすることが occasionally ありました。文脈を欠いた指示となり、それらに意味を与えるスキル本文がないままです。出力は微妙に間違っており、なぜそうなるのか理解できませんでした。なぜなら、参照ファイル単体で見れば問題ないように見えるからです。それがスキルレベルの可視性へと昇格していたことに気づいていませんでした。
解決策は各ファイルにつき 1 行だけでした。参照ファイルからのフロントマターを削除することです。それらはスキルではありません。他のスキルが指し示す章なのです。
これは、20% から 7% への話です。
複数のモジュールやメッセージシステムにわたって文脈を捕捉するスキルを構築した際、私はすべてを一つの SKILL.md にまとめました。よりクリーンに見えると思ったからです。1 つのファイル、1 つの真実源。読みやすく、編集も容易でした。
しかしそれは同時に、スキルがトリガーされるたびにエージェントが 1,200 行に及ぶファイル全体を読み込むことを意味しました。モジュールマップ、契約、パターン、そして落とし穴です。タスクに必要なものがそのうちの 4 つのうち 2 つだけだったとしても同様でした。
それを 180 行の骨格と 3 つの参照ファイルに分割したことで、コンテキスト消費量は 20% から 7% に削減されました。同じタスク、同じ出力、同じモデルです。
これは累積します。コストが 20% ではなく 7% のスキルであれば、同じコンテキスト予算内に 3 つインストールでき、圧縮前にセッションを長く実行でき、長期のタスクで崖(失敗点)にぶつかる回数を減らせます。この節約は局所的なものではありません。下流のあらゆる場所で現れます。
私はチームメイトとあるスキルを共有しましたが、そのスキルは誤ったディレクトリでビルドコマンドを実行しました。
私の指示には「*modules/web* に移動してビルドを実行」といった内容が含まれていました。これは私のリポジトリでは機能していました。しかし、チームメイトのリポジトリには 4 つのモジュールがあり、「modules/web」は存在せず、「packages/frontend/web」がありました。そのスキルは黙って間違ったディレクトリを選択し、誤った場所に出力を生成しました。エラーはありません。ただ、結果が間違っているだけでした。
解決策は、パスを宣言するのではなく、エージェントに正しいパスを*発見*させるような指示を書くことでした。ビルド設定を検索し、package.json でモジュールを特定します。仮定する前にワークスペースの構造を読み込みます。スキルはより抽象的になりましたが、移植性が高まりました。
これは共有したときに初めて現れる失敗モードです。自分のマシンだけでスキルを実行する場合のみであれば、何でもハードコードしても機能します。しかし、別のエンジニアが実行した瞬間、すべての暗黙的な仮定がバグとして表面化します。
私のモノレポでは Turborepo を使用しています。設定を正しく解決するには、ビルドコマンドはリポジトリのルートから実行する必要があります。モジュールディレクトリの内部からビルドを実行してもビルド自体は走りますが、キャッシュミスが発生し、依存関係グラフが誤って読み取られ、出力が微妙に間違ったものになります。
エージェントのデフォルトは妥当でした:「私は *web* モジュールで作業しているので、*web* モジュールからビルドを実行します」。これはリポジトリの 90% で正しいアプローチです。しかし、このケースでは間違っていました。
指示に「なぜそうするのか」を説明する量をいくら追加しても、これを防ぐことはできませんでした。間違いは概念的な誤りではなく、環境的な問題でした。エージェントの事前知識(prior)は平均的には正しかったのです。私の環境が平均的ではなかったのです。
解決策は、"Gotchas" セクションに1行追加しただけです:「*turbo build* は常にリポジトリのルートから実行し、モジュール内部からは決して実行しないでください」。たった1行です。次にエージェントがビルドコマンドを実行しようとしたとき、この注意点を参照して正しく動作しました。
これが"Gotchas"セクションの役割です。エージェントには妥当なデフォルトがあります。しかし、あなたの環境は平均的ではありません。そのギャップこそが"Gotchas"セクション全体の役割であり、成熟したスキルドキュメントにおいて、これを長期的に最も重要な維持対象として扱う理由でもあります。
最も深い誤り。私は評価(evals)を書きませんでした。
私の個人的な Claude デスクトップ用にライティングスキルを構築しました。これは Scott Adams のライティング原則 に基づいています:短い文、能動態、要点の先出し、1 段落に 1 つのアイデア。これを Sonnet 4.6 で調整しました。私の意図した通りに機能し、ドラフトは清潔で、直接的で、私の声で書かれたものになりました。
その後、Opus にアップグレードしました。より良いモデルだと考え、より良い出力が得られると期待していました。
しかし、出力はむしろ悪化しました。文の長さは 5〜7 語に収まりました。技術的には短いです。しかし、不自然で切れ切れです。リズムも流れもなく、まるで私の文章とは読めません。その文章は、散文を装った箇条書きのように感じられました。
何が起きたのかは微妙な違いでした。Sonnet は「短い文を書く」という指示を読み取り、判断を加えました。要点を鋭くするために短くなるべき箇所では短く、リズムが必要となる箇所では長くしました。その精神を理解していたのです。一方、Opus は同じ指示を読み取り、文字通りに従いました。すべての文が厳格な制約となり、例外はありませんでした。
より能力の高いモデルは、「良い文章」がどのようなものかについて、より強い事前知識を持っています。そのモデルにとっての明確な文章とは、インターネット上の良い文章の統計的な中心です。私の声は統計的中心ではありません。Opus は自分の美的感覚へと強く引き寄せられ、私のスタイルから遠ざかりました。
***一つのモデルに調整されたスキルは、そのモデルの能力だけでなく、そのモデルのコンプライアンス特性にも適合するように較正されています。*
より能力の高いモデルが自動的に最適な選択とは限りません。場合によっては、指示に従うのではなく解釈してしまうため、むしろ悪くなることもあります。
私は評価(evals)を持っていませんでした。どれほどずれてしまったか、どの指示が過度に適用されたか、あるいは合格する出力が量的にどのようなものかを把握する方法がありませんでした。「私らしさ」というものをテストで検証できる形で定義したこともありませんでした。
Anthropic のスキル作成者であるツール(チームが社内ですぐにスキルを構築するために使用するもの)には、明示的な評価手法があります。その中核となる動きは「ペア実行」です。各テストプロンプトに対してエージェントを 2 回実行します。1 回はスキルありで、もう 1 回はスキルなしで実行します。出力が良いかどうかを測定しているのではありません。「ベースラインよりも優れているか」、そして「どれほど優れているか」を測定しているのです。
***A skill tuned on one model is calibrated to that model's compliance characteristics, not just its capabilities.*
A more capable model isn't automatically a better fit. Sometimes it's worse, because it interprets your instructions instead of following them.
I had no evals. No way to know how much had drifted, which instructions were being over-applied, or what a passing output even looked like quantitatively. I'd never defined what "sounds like me" meant in terms a test could check.
Anthropic's skill-creator, the tool the team uses to build their own skills internally, has an explicit eval methodology. The core move is *paired runs*: for every test prompt, run the agent twice. Once with the skill, once without. You're not measuring whether the output is good. You're measuring whether it's *better than baseline*, and by how much.
ライティングスキルにおいて、すべての主張をスクリプト化できるわけではありません。しかし、出力長さ、文数、平均文長、読みやすさスコアなどは可能です。残りは構造化された人間のレビューであり、以前の出力と新しい出力を並列に配置し、メモ欄を設けます。これが Anthropic の skill-creator における eval-viewer が生成するものです。
私は現在、各スキルごとに小さな「ゴールデンセット」を保持しています。これは、基盤となるモデルが変更された際に私の文体が drifting(逸脱)しないようにするための実践であり、この手法は今後の自動化されたスキル検証に関する記事で詳しく解説します。現実的なプロンプトを 3〜4 個用意し、モデルのバージョンアップやスキルの編集ごとにそのスイートを実行し、差分を確認します。
*テスト時には動作した*という事実は証拠ではありません。測定が行われていないことの証左に過ぎません。
4 つの重要な点を心に留めておいてください。
スキルはプロンプトではなく、ローダー仕様です。 Frontmatter はルーティング機構であり、SKILL.md はトリガーされたペイロードです。参照やスクリプトは後続の章として延期されます。このアーキテクチャを理解すれば、あらゆる作成上の判断は「このコンテンツをどのレベルに属させるか」という問いになります。
アーキテクチャがコストを決定します。 同じ指示でも、不適切な形状で記述されると、コンテキストウィンドウの 3 倍もの容量を消費する可能性があります。このペナルティは、インストールされたすべてのスキルと、実行されるすべてのターンにわたって複合的に蓄積されます。解決策は文章レベルではなく、構造的なものです。
エージェントには妥当な事前知識がありますが、あなたの環境にはありません。 罠が存在するのは、モデルのデフォルトが平均的には正しい一方で、あなたの状況は平均的ではないからです。ワークスペースパス、ビルドシステム、チームの慣習:これらすべてがモデルのトレーニングデータに含まれているわけではありません。それらはスキルの中に存在させる必要があります。
モデルのアップグレードにはコストがかかります。 1 つのモデル向けに調整されたスキルは、そのモデルのコンプライアンス特性に合わせてキャリブレーションされています。より能力の高いモデルは指示に従うのではなく解釈しますが、個人的または組織的な声をエンコードしたスキルにおいては、この解釈こそが失敗となります。アップグレードが役立ったのか悪影響を及ぼしたのかを知る唯一の方法は、それを測定することです。
*次号:* 埋め込みの内部構造。高次元空間でコサイン類似度が奇妙になる理由。対照的学習が実際に何を学ぶのか。なぜ汎用ウェブ埋め込みモデルがあなたのドメインデータで静かに失敗するのか、そして微調整すべきかより良いベースモデルを選ぶべきかをどう見極めるか。
*その後:* AGENTS.md。エージェントに指示を追加するとむしろ悪化するという経験的な発見。138 の本番リポジトリを対象とした Gloaguen 他による研究。なぜあなたのコンテキストファイルが助けになるよりも害を及ぼしている可能性があるのか。
*INTERNALS.md は、本番環境の AI およびデータシステムが実際にどのように動作するかについての技術シリーズです。チュートリアルはありません。フレームワークの布教もありません。ただ、その下層にあるものだけです。
*これが役に立ったのであれば、最も良い行動は、関心を持つエンジニア 1 人に共有することです。*
- エージェント・スキル概要、Claude API ドキュメント
- エージェント・スキルのベストプラクティス、Claude API ドキュメント
- Barry Zhang, Keith Lazuka, Mahesh Murag による「エージェントに Agent Skills を実装して現実世界に対応させる」、Anthropic Engineering、2025 年 10 月
- skill-creator/SKILL.md、Anthropic スキルリポジトリ
- エージェント・スキルオープンスタンダード、2025 年 12 月
- 『あなたがより良いライターになる日』、Lakshmanan Meiyappan
- Scott Adams のオリジナル投稿(Internet Archive を経由)
原文を表示
A skill is a small program.
It has three execution stages: 1\ what loads every turn, 2\ what loads on invocation, and 3\ what loads on demand. Because a skill is a program, it suffers from typical software rot—environment drift, version sensitivity, and silent, non-reproducible failures.
You’ll see these failures in specific shapes. A skill that cost 20% of your context window, silently, before the agent did any work. A skill that worked perfectly until you shared it with a teammate, and ran the build in the wrong directory. A skill tuned carefully on one model, producing worse output the moment you upgraded to a better one.
These aren’t separate bugs. They’re four faces of the same misunderstanding: treating a loader specification like a prompt.
This post is about what skills actually are underneath, and why understanding the runtime changes everything you do at the surface.
A note on scope. Skills aren’t a Claude-only thing anymore. Anthropic published the SKILL.md format as an open standard in December 2025, and the same files now work across Claude Code, Kiro, Cursor, Codex CLI, and others. The mental model in this post applies to all of them. I’ll use *Claude* as shorthand for the agent harness reading the skill. Swap in your runtime of choice.
The first time I wrote a Skill, I thought I was writing a long prompt the agent would consult.
I wrote one big SKILL.md. Maybe 1,200 lines. Workflow at the top, a map of every module in our codebase, example code, message contracts between services, framework-specific patterns, and at the bottom a list of every gotcha I knew. It worked. It also consumed about 20% of the context window before the agent did any actual work.
I rewrote it. Same instructions, same output, different architecture: a 180-line SKILL.md that pointed at three reference files and one helper script. The new version cost 7%.
The instructions didn’t change. The architecture did. That’s where the 3× difference lived, and it was the first sign that I was not, in fact, writing a long prompt.
A prompt is static text. You write it, you ship it, the model reads all of it on every turn. Skills don’t work like that. Skills are a *loader specification*. You’re describing what should be in context, when, and at what cost. The text matters, but the structure decides what survives the trip into the model’s working memory.
That reframe is the whole post. Everything else falls out of it.
*A real skill restructure. Same task, same model, same output. The 3× difference came from where the instructions lived, not what they said.*
Skills run on a principle Anthropic calls *progressive disclosure*. The official documentation defines it plainly:
Skills can contain three types of content, each loaded at different times.
This is why two skills with identical instructions can behave completely differently. One loads 180 lines on demand; the other dumps 1,200 lines every turn.
Anthropic built these levels to protect your context window. If a skill front-loads everything, it crowds out the conversation history and tool outputs. By using progressive disclosure, you stop paying for “just in case” instructions and only pay for “just in time” execution.
*Each level loads at a different time, with a different cost. Most authors put everything at Level 2.*
Level 1: Metadata. The name and description from YAML frontmatter. Always loaded, every turn. The official docs put this at roughly 100 tokens per skill installed. The agent uses the description to decide whether the skill is relevant. It’s a routing decision, not a usage decision. This is the most important level to get right. If the description is wrong, nothing else matters.
Level 2: SKILL.md body. The procedural instructions. Loaded only when the agent decides the skill applies, by reading the file via bash. Anthropic’s best practices documentation puts the recommended ceiling at 500 lines. This is where most people pile on content they shouldn’t.
Level 3: References and scripts. Bundled files referenced from SKILL.md. References are markdown the agent reads only when the body points to them. Scripts are executable code the agent *runs*: output enters context, the source code does not. Effectively unlimited.
The Anthropic engineering team (Barry Zhang, Keith Lazuka, and Mahesh Murag) described it in their October 2025 announcement as: *“Like a well-organized manual that starts with a table of contents, then specific chapters, and finally a detailed appendix, skills let Claude load information only as needed.”*
Get the architecture right and your skill costs almost nothing until it earns its place. Get it wrong and you pay every turn.
Picture a kitchen during dinner service.
*The chef’s attention is the scarce resource. Same as the agent’s context window.*
There’s a pinboard on the wall with recipe titles and one-line summaries. *Pasta Carbonara: Italian classic, use when guest wants creamy pasta with bacon.* The chef glances at it constantly. It’s small enough to hold in peripheral vision. That’s frontmatter.
When a guest orders, the chef picks the matching card and pulls down the full recipe. Ingredients, steps, technique notes. The recipe is not on the wall. It would be too cluttered, too distracting, too much to scan during service. It comes down only when needed. That’s SKILL.md.
The recipe sometimes says *for the sauce, see Sauce Reference, page 47*. The chef walks to the binder, opens to page 47, reads only that page. Doesn’t read the whole binder. That’s references/.
In the corner, a stand mixer. The recipe says *use the mixer for three minutes*. The chef does not read the mixer’s circuit diagram. The chef hands it ingredients, presses a button, gets output. That’s scripts/.
The metaphor holds under pressure, which is the only test of a metaphor. Every failure mode I hit in my own skills traces back to violating the kitchen.
When I first started migrating my workflows to the SKILL.md, I treated the runtime like a smart intern who could “just figure it out.”
I was wrong. Because the skills runtime is a deterministic loader, minor architectural choices—like where you put a single line of YAML—can silently break the agent’s reasoning. These aren’t just bugs; they are antipatterns. Each one below represents a moment where I violated the “Kitchen” logic and paid for it in context drift, high latency, or hallucinated outputs.
The first thing I got wrong, before I understood progressive disclosure existed.
I added YAML frontmatter to my reference files because SKILL.md had it, and the references felt important enough to deserve metadata. I didn’t realize what frontmatter actually does.
Frontmatter is what gets loaded into the system prompt at startup. Every file with frontmatter contributes its name and description to the always-loaded set. The pinboard. Adding frontmatter to a reference file pins it to the wall as if it were a top-level skill. It isn’t. Now the pinboard shows fifty entries instead of five, most of them sub-pages that were never meant to be visible at routing time.
In practice: the agent would occasionally trigger a reference file directly instead of the parent skill. Instructions out of context, without the skill body that gave them meaning. The output was subtly wrong and I couldn’t figure out why, because the reference file looked fine in isolation. I didn’t realize it had been promoted to skill-level visibility.
The fix was one line per file: delete the frontmatter from references. They’re not skills. They’re chapters that other skills point to.
This is the 20%-to-7% story.
When I built a skill to capture context across multiple modules and message systems, I put everything in one SKILL.md. It seemed cleaner. One file, one source of truth. Easy to read, easy to edit.
It also meant that every time the skill triggered, the agent loaded the entire 1,200-line file. Module map, contracts, patterns, and gotchas. Even when the task only needed two of those four.
Splitting it into a 180-line spine with three reference files dropped context consumption from 20% to 7%. Same task, same output, same model.
This compounds. A skill that costs 7% instead of 20% means you can install three of them in the same context budget, run longer sessions before compaction, hit fewer cliffs on long-horizon tasks. The savings aren’t local. They show up everywhere downstream.
I shared a skill with a teammate and it ran the build command in the wrong directory.
My instructions said something like *navigate to *modules/web* and run the build*. That worked in my repo. My teammate’s repo had four modules. modules/web didn’t exist; they had packages/frontend/web. The skill silently picked the wrong directory and produced output in the wrong place. No error. Just wrong output.
The fix was to write instructions that ask the agent to *discover* the right path rather than declare it. Search for the build configuration. Identify the module by its package.json. Read the workspace structure before assuming. The skill became more abstract, but it became portable.
This is the failure mode that doesn’t appear until you share. If you only ever run a skill on your own machine, you can hardcode anything and it will work. The moment another engineer runs it, every implicit assumption surfaces as a bug.
My monorepo uses Turborepo. The build command has to run from the repo root for the configuration to resolve correctly. If you run build from inside a module directory, the build still runs. But the cache misses, the dependency graph gets misread, and the output is subtly wrong.
The agent’s default was reasonable: *I’m working in the *web* module, so I’ll run the build from the *web* module.* That’s correct in 90% of repos. It was wrong in this one.
No amount of “explain the why” in the instructions would have prevented it. The wrongness wasn’t conceptual; it was environmental. The agent’s prior was correct on average. My environment wasn’t average.
The fix was a single line in a Gotchas section: *Always run *turbo build* from the repository root, never from inside a module.* One line. The next time the agent reached for the build command, it consulted the gotcha and ran correctly.
This is what Gotchas are for. The agent has reasonable defaults. Your environment isn’t average. That gap is the whole job of the Gotchas section, and it’s why mature skills treat it as the most important section to maintain over time.
The deepest mistake. I didn’t write evals.
I built a writing skill for my personal Claude desktop. It was based on Scott Adams’ writing principles: short sentences, active voice, front-loaded points, one idea per paragraph. I tuned it on Sonnet 4.6. It worked exactly the way I wanted: drafts came out clean, direct, in my voice.
Then I upgraded to Opus. Better model, I assumed. Better output.
The output was worse. Every sentence ran 5 to 7 words. Technically short. But choppy. No rhythm, no flow, nothing that read like me. The writing felt like bullet points dressed as prose.
What happened is subtle. Sonnet read “write short sentences” and applied judgment: short where brevity sharpened the point, longer where the rhythm needed it. It understood the spirit. Opus read the same instruction and followed it literally. Every sentence, hard constraint, no exceptions.
The more capable model has stronger priors about what “good writing” looks like. Its version of clear prose is the statistical center of good writing on the internet. My voice isn’t the statistical center. Opus pulled hard toward its own aesthetic, and away from mine.
A skill tuned on one model is calibrated to that model’s compliance characteristics, not just its capabilities.
A more capable model isn’t automatically a better fit. Sometimes it’s worse, because it interprets your instructions instead of following them.
I had no evals. No way to know how much had drifted, which instructions were being over-applied, or what a passing output even looked like quantitatively. I’d never defined what “sounds like me” meant in terms a test could check.
Anthropic’s skill-creator, the tool the team uses to build their own skills internally, has an explicit eval methodology. The core move is *paired runs*: for every test prompt, run the agent twice. Once with the skill, once without. You’re not measuring whether the output is good. You’re measuring whether it’s *better than baseline*, and by how much.
For a writing skill, not all assertions are scriptable. But some are: output length, sentence count, average sentence length, readability score. The rest is structured human review, with the previous output alongside the new one and a notes field. That’s what Anthropic’s eval-viewer in skill-creator produces.
I now keep a small 'Golden Set' per skill—a practice we’ll dissect in an upcoming post on automated skill validation—to ensure my voice doesn't drift when the underlying model changes. Three or four realistic prompts. Rerun the suite on every model bump, every skill edit. Check the deltas.
*It worked when I tested it* is not evidence. It’s the absence of measurement.
Four things should stick.
Skills are loader specifications, not prompts. Frontmatter is a routing mechanism. SKILL.md is a triggered payload. References and scripts are deferred chapters. Once you see the architecture, every authoring decision becomes a question of *which level does this content belong at?*
Architecture decides cost. The same instructions, in the wrong shape, can consume 3× the context window. That penalty compounds across every skill installed and every turn taken. The fix is structural, not prose-level.
The agent has reasonable priors. Your environment doesn’t. Gotchas exist because the model’s defaults are correct on average and your situation isn’t average. Workspace paths, build systems, team conventions: none of it lives in the model’s training. It has to live in the skill.
A model upgrade is not free. A skill tuned on one model is calibrated to that model’s compliance characteristics. A more capable model interprets your instructions instead of following them, and for skills that encode personal or organizational voice, that interpretation is the failure. The only way to know if an upgrade helped or hurt is to measure it.
*Next issue:* Embeddings Internals. Why cosine similarity gets weird in high dimensions. What contrastive training actually learns. Why a general-web embedding model will silently fail on your domain data, and how to know when to fine-tune versus pick a better base model.
*Then:* AGENTS.md, and the empirical finding that adding more instructions to your agent often makes it worse. The Gloaguen et al. study on 138 production repositories. Why your context file might be hurting more than it’s helping.
*INTERNALS.md is a technical series on how production AI and Data systems actually work. No tutorials. No framework evangelism. Just the layer beneath.*
*If this was useful, the best thing you can do is share it with one engineer who’d care.*
- Agent Skills overview, Claude API documentation
- Agent Skills best practices, Claude API documentation
- Equipping agents for the real world with Agent Skills, Barry Zhang, Keith Lazuka, Mahesh Murag, Anthropic Engineering, October 2025
- skill-creator/SKILL.md, Anthropic skills repository
- Agent Skills open standard, December 2025
- The Day You Became a Better Writer, Lakshmanan Meiyappan
- Scott Adams’ original post, via Internet Archive
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み