スキルクリエイター
スクリプト、リファレンス、アセットを備えた再利用可能なスキルの範囲設定、構造化、パッケージ化に関するエージェント スキルのライフサイクル ガイド。
出典: anthropics/skills (MIT) を基にしたコンテンツ。
新しいスキルを作成し、繰り返し改善するためのスキル。
大まかに言うと、スキルを作成するプロセスは次のようになります。
- スキルに何をさせたいのか、そしてそれをどのように行うべきかを大まかに決定します
- スキルの下書きを書く
- いくつかのテスト プロンプトを作成し、それらに対して claude-with-access-to-the-skill を実行します。
- ユーザーが結果を定性的および定量的に評価できるようにする
- 実行がバックグラウンドで行われている間に、定量的評価が存在しない場合はドラフトを作成します (存在する場合は、そのまま使用することも、何かを変更する必要があると感じた場合は変更することもできます)。次に、それらをユーザーに説明します (または、すでに存在する場合は、すでに存在するものについて説明します)。
eval-viewer/generate_review.pyスクリプトを使用して、ユーザーに確認できる結果を表示し、定量的な指標も確認できるようにします。
- 結果に対するユーザーの評価からのフィードバックに基づいてスキルを書き直します (また、定量的なベンチマークから明らかになった明らかな欠陥がある場合も同様です)。
- 満足するまで繰り返します
- テスト セットを拡張して、より大規模な規模で再試行してください
このスキルを使用するときの仕事は、ユーザーがこのプロセスのどの段階にいるのかを把握し、そこに飛び込み、これらの段階を進んでいくのを支援することです。たとえば、「X のスキルを作りたい」というようなことかもしれません。意味を絞り込み、下書きを書き、テスト ケースを書き、どのように評価するかを考え、すべてのプロンプトを実行し、それを繰り返すことができます。
一方で、もしかしたらすでにスキルの草案を持っているかもしれません。この場合、ループの評価/反復部分に直接進むことができます。
もちろん、常に柔軟である必要があります。ユーザーが「たくさんの評価を実行する必要はない、ただ一緒にいてほしい」という場合は、代わりにそうすることができます。
次に、スキルが完了した後 (ただし、順序は柔軟です)、スキルのトリガーを最適化するために、完全に別のスクリプトが用意されているスキル記述改善プログラムを実行することもできます。
かっこいい?いいね。
ユーザーとのコミュニケーション
スキル クリエーターは、コーディング専門用語に精通した幅広い人々によって使用される可能性があります。聞いたことがない方のために説明します (そして、どうしてわかるでしょうか。それが始まったのはごく最近のことです)。現在、クロードの力によって配管工が端末を開放し、親や祖父母が「npm のインストール方法」をグーグルで検索するようになっている傾向があります。一方で、ユーザーの大部分はおそらくかなりコンピューターに精通しています。
したがって、コミュニケーションの表現方法を理解するために、文脈の手がかりに注意を払ってください。デフォルトの場合は、次のようになります。
- 「評価」と「ベンチマーク」は境界線だけどOK
- 「JSON」と「アサーション」については、ユーザーが説明せずに使用する前に、それらが何であるかを知っているという真剣な合図が必要です。
疑問がある場合は用語を簡単に説明しても問題ありません。ユーザーが理解できるかどうかわからない場合は、短い定義で用語を明確にしてもかまいません。
スキルの作成
意図のキャプチャ
まずはユーザーの意図を理解することから始めましょう。現在の会話には、ユーザーがキャプチャしたいワークフローがすでに含まれている可能性があります (例: 「これをスキルに変える」など)。その場合は、まず会話履歴から、使用したツール、一連の手順、ユーザーが行った修正、観察された入力/出力形式などの回答を抽出します。ユーザーはギャップを埋める必要がある場合があるため、次のステップに進む前に確認する必要があります。
- クロードはこのスキルで何をできるようになるでしょうか?
- このスキルはいつ発動するべきですか? (ユーザーのフレーズ/コンテキスト)
- 予想される出力形式は何ですか?
- スキルが機能することを確認するためにテストケースを設定する必要がありますか?客観的に検証可能な出力 (ファイル変換、データ抽出、コード生成、固定ワークフロー ステップ) を備えたスキルは、テスト ケースから恩恵を受けます。主観的なアウトプット(文体、芸術)を伴うスキルには、多くの場合、それらは必要ありません。スキルのタイプに基づいて適切なデフォルトを提案しますが、決定はユーザーに任せます。
インタビューと調査
特殊なケース、入出力形式、サンプル ファイル、成功基準、依存関係について積極的に質問してください。この部分が解決されるまで、テスト プロンプトを作成するのを待ちます。
利用可能な MCP を確認します - 研究に役立つ場合 (ドキュメントの検索、類似のスキルの検索、ベスト プラクティスの検索)、利用可能な場合はサブエージェントを介して並行して研究し、それ以外の場合はインラインで研究します。ユーザーの負担を軽減するためにコンテキストを準備してください。
SKILL.mdを書く
ユーザーインタビューに基づいて、次の要素を入力します。
- 名前: スキル識別子
- 説明: トリガーするタイミングとその動作。これは主要なトリガーメカニズムであり、スキルの動作と、それを使用する特定のコンテキストの両方が含まれます。 「いつ使用するか」に関する情報はすべて、本文ではなくここに記載されます。注: 現在、クロードはスキルを「トリガー不足」にする傾向があり、役立つ場合にスキルを使用しません。これに対処するには、スキルの説明を少し「強引」にしてください。したがって、たとえば、「Anthropic の内部データを表示するためのシンプルで高速なダッシュボードを構築する方法。」の代わりに、「Anthropic の内部データを表示するためのシンプルで高速なダッシュボードを構築する方法。ユーザーがダッシュボード、データの視覚化、内部メトリクスについて言及したとき、またはあらゆる種類の企業データを表示したいときは、たとえ明示的に「ダッシュボード」を要求していなくても、必ずこのスキルを使用してください。」と書くことができます。
- 互換性: 必要なツール、依存関係 (オプション、ほとんど必要ありません)
- 残りのスキル:)
スキルライティングガイド
スキルの構造
skill-name/
SKILL.md (required)
YAML frontmatter (name, description required)
Markdown instructions
Bundled Resources (optional)
scripts/ - Executable code for deterministic/repetitive tasks
references/ - Docs loaded into context as needed
assets/ - Files used in output (templates, icons, fonts)漸進的開示
スキルには 3 レベルのロード システムが使用されます。
- メタデータ (名前 + 説明) - 常にコンテキスト内にあります (~100 ワード)
- SKILL.md body - スキルがトリガーされるたびにコンテキスト内に表示されます (500 行未満が理想的)
- バンドルされたリソース - 必要に応じて (無制限、スクリプトはロードせずに実行可能)
これらの単語数はおおよそのものであり、必要に応じてさらに長くしても構いません。
主なパターン:
- SKILL.md は 500 行以内にしてください。この制限に近づいている場合は、スキルを使用するモデルが次にフォローアップする必要がある場所についての明確なポインタとともに、階層の追加レイヤーを追加します。
- SKILL.md からファイルを明確に参照し、いつ読み込むべきかについてのガイダンスを提供します
- 大きな参照ファイル (300 行を超える) の場合は、目次を含めます。
ドメイン編成: スキルが複数のドメイン/フレームワークをサポートする場合、バリアントごとに編成します。
cloud-deploy/
SKILL.md (workflow + selection)
references/
aws.md
gcp.md
azure.mdクロードは、関連する参照ファイルのみを読み取ります。
驚きの欠如の原則
言うまでもないことですが、スキルにはマルウェア、エクスプロイト コード、またはシステム セキュリティを侵害する可能性のあるコンテンツが含まれていてはなりません。スキルの内容が説明されていても、その意図がユーザーを驚かせるものであってはなりません。誤解を招くスキルや、不正アクセス、データの引き出し、その他の悪意のある活動を促進するように設計されたスキルを作成するリクエストに応じないでください。 「XYZとしてのロールプレイ」のようなものはOKです。
パターンの書き方
指示では命令形を使用することを好みます。
出力形式の定義 - 次のように実行できます。
## Report structure
ALWAYS use this exact template:
# [Title]
## Executive summary
## Key findings
## Recommendations例のパターン - 例を含めると便利です。次のようにフォーマットできます (ただし、「入力」と「出力」が例にある場合は、少し変更する必要があるかもしれません)。
## Commit message format
**Example 1:**
Input: Added user authentication with JWT tokens
Output: feat(auth): implement JWT-based authentication文体
強引なカビ臭い MUST の代わりに、なぜ物事が重要なのかをモデルに説明してみてください。心の理論を使用し、スキルを特定の例に限定したものではなく、一般的なものにするように努めてください。まずは下書きを書き、それを新鮮な目で見て改善していきます。
テストケース
スキルのドラフトを作成した後、実際のユーザーが実際に言うような、現実的なテスト プロンプトを 2 ~ 3 つ考え出します。それらをユーザーと共有します: [この言葉をそのまま使用する必要はありません] 「試してみたいテスト ケースがいくつかあります。これらは適切ですか? それともさらに追加しますか?」次に、それらを実行します。
テスト ケースをevals/evals.jsonに保存します。アサーションはまだ書かず、プロンプトだけを書きます。実行の進行中に、次のステップでアサーションの草稿を作成します。
{
"skill_name": "example-skill",
"evals": [
{
"id": 1,
"prompt": "User's task prompt",
"expected_output": "Description of expected result",
"files": []
}
]
}完全なスキーマについては、「references/schemas.md」を参照してください (後で追加するassertionsフィールドを含む)。
テストケースの実行と評価
このセクションは 1 つの連続したシーケンスです。途中で停止しないでください。/skill-testやその他のテスト スキルは使用しないでください。
結果をスキル ディレクトリの兄弟として<skill-name>-workspace/に置きます。ワークスペース内で、反復ごとに結果を整理し (iteration-1/、iteration-2/など)、その中で各テスト ケースがディレクトリ (eval-0/、eval-1/など) を取得します。これらすべてを事前に作成するのではなく、作業の途中でディレクトリを作成するだけです。
ステップ 1: 同じターンにすべてのラン (スキルとベースラインあり) を生成する
テスト ケースごとに、同じターンに 2 つのサブエージェント (スキルを持つ 1 つとスキルを持たない 1 つ) を生成します。これは重要です。最初にスキル付きの実行を生成し、後でベースラインに戻ってこないでください。すべてを一度に起動すると、すべてがほぼ同時に終了します。
スキル付きラン:
Execute this task:
- Skill path: <path-to-skill>
- Task: <eval prompt>
- Input files: <eval files if any, or "none">
- Save outputs to: <workspace>/iteration-<N>/eval-<ID>/with_skill/outputs/
- Outputs to save: <what the user cares about - e.g., "the .docx file", "the final CSV">ベースラインの実行 (同じプロンプトですが、ベースラインはコンテキストによって異なります):
- 新しいスキルの作成: スキルはまったくありません。同じプロンプト、スキルパスなし、
without_skill/outputs/に保存。 - 既存のスキルの改善: 古いバージョン。編集する前に、スキル (
cp -r <skill-path> <workspace>/skill-snapshot/) のスナップショットを作成し、そのスナップショットでベースライン サブエージェントをポイントします。old_skill/outputs/に保存します。
テスト ケースごとにeval_metadata.jsonを書き込みます (現時点ではアサーションは空でもかまいません)。各 eval には、「eval-0」だけでなく、テスト対象に基づいてわかりやすい名前を付けます。ディレクトリにもこの名前を使用します。この反復で新しいまたは変更された eval プロンプトを使用する場合は、新しい eval ディレクトリごとにこれらのファイルを作成します。前の反復から引き継がれると想定しないでください。
{
"eval_id": 0,
"eval_name": "descriptive-name-here",
"prompt": "The user's task prompt",
"assertions": []
}ステップ 2: 実行の進行中に、アサーションのドラフトを作成する
実行が終了するのをただ待つだけではなく、この時間を生産的に使うことができます。各テスト ケースの定量的アサーションの草案を作成し、ユーザーに説明します。アサーションがすでにevals/evals.jsonに存在する場合は、それらを確認し、何をチェックするかを説明します。
優れたアサーションは客観的に検証可能で、わかりやすい名前が付けられています。結果を一目見た人がそれぞれのチェック内容をすぐに理解できるように、ベンチマーク ビューアで明確に読み取れる必要があります。主観的なスキル (書き方、デザインの品質) は定性的に評価される方が良いため、人間の判断が必要なものに主張を押し付けないでください。
作成されたアサーションを使用して、eval_metadata.jsonファイルとevals/evals.jsonを更新します。また、ビューアに表示される内容、つまり定性的な出力と定量的なベンチマークの両方についてもユーザーに説明してください。
ステップ 3: 実行が完了したら、タイミング データをキャプチャする
各サブエージェント タスクが完了すると、total_tokensおよびduration_msを含む通知を受け取ります。このデータをすぐに実行ディレクトリのtiming.jsonに保存します。
{
"total_tokens": 84852,
"duration_ms": 23332,
"total_duration_seconds": 23.3
}これは、このデータを取得する唯一の機会です。データはタスク通知を通じて取得され、他の場所には保持されません。各通知をバッチ処理するのではなく、受信したときに処理します。
ステップ 4: 採点、集計、ビューアの起動
すべての実行が完了したら、次のようにします。
-
各実行を採点 -
agents/grader.mdを読み取り、出力に対して各アサーションを評価する採点サブエージェント (またはインラインで採点) を生成します。結果を各実行ディレクトリのgrading.jsonに保存します。 grading.json の期待配列では、フィールドtext、passed、およびevidence(name/met/detailsまたはその他のバリアントではない) を使用する必要があります。ビューアーはこれらの正確なフィールド名に依存します。プログラムでチェックできるアサーションの場合は、スクリプトを目視するのではなく、スクリプトを作成して実行します。スクリプトはより高速で信頼性が高く、反復間で再利用できます。 -
ベンチマークに集約 - スキル作成者ディレクトリから集約スクリプトを実行します。
python -m scripts.aggregate_benchmark <workspace>/iteration-N --skill-name <name>これにより、各構成の pass_rate、time、トークン、平均 stddev とデルタを含む
benchmark.jsonおよびbenchmark.mdが生成されます。 Benchmark.json を手動で生成する場合、ビューアが期待する正確なスキーマについては、references/schemas.mdを参照してください。 各 with_skill バージョンを、対応するベースラインバージョンの前に置きます。 -
アナリスト パスを実行します - ベンチマーク データと、集計統計に隠れている可能性のある表面パターンを読み取ります。何を探すべきかについては、
agents/analyzer.md(「ベンチマーク結果の分析」セクション) を参照してください。スキルに関係なく常に合格するアサーション (無差別)、分散の高い eval (不安定な可能性がある)、時間とトークンのトレードオフなどです。 -
ビューアを起動して、定性的な出力と定量的なデータの両方を表示します。
nohup python <skill-creator-path>/eval-viewer/generate_review.py \ <workspace>/iteration-N \ --skill-name "my-skill" \ --benchmark <workspace>/iteration-N/benchmark.json \ > /dev/null 2>&1 & VIEWER_PID=$!反復 2 以降の場合は、
--previous-workspace <workspace>/iteration-<N-1>も渡します。コワーク/ヘッドレス環境:
webbrowser.open()が使用できない場合、または環境にディスプレイがない場合は、サーバーを起動する代わりに、--static <output_path>を使用してスタンドアロン HTML ファイルを作成します。ユーザーが「すべてのレビューを送信」をクリックすると、フィードバックはfeedback.jsonファイルとしてダウンロードされます。ダウンロード後、次の反復で取得できるように、feedback.jsonをワークスペース ディレクトリにコピーします。
注: ビューアを作成するには、generate_review.py を使用してください。カスタム HTML を記述する必要はありません。
- ユーザーに次のようなことを伝えます: 「ブラウザで結果を開いたところです。タブが 2 つあります。[出力] では各テスト ケースをクリックしてフィードバックを残すことができ、[ベンチマーク] では定量的な比較が表示されます。完了したら、ここに戻ってきて知らせてください。」
ユーザーがビューアで見るもの
「出力」タブには、一度に 1 つのテスト ケースが表示されます。
- プロンプト: 与えられたタスク
- 出力: スキルが生成したファイル。可能な場合はインラインでレンダリングされます。
- 前の出力 (反復 2+): 最後の反復の出力を示す折りたたまれたセクション
- 正式な成績 (採点が実行された場合): アサーションの合格/不合格を示す折りたたまれたセクション
- フィードバック: 入力時に自動保存されるテキストボックス
- 前回のフィードバック (反復 2+): 前回のコメント。テキストボックスの下に表示されます。
[ベンチマーク] タブには、各構成の合格率、タイミング、トークン使用量などの統計の概要が、評価ごとの内訳とアナリストの観察とともに表示されます。
ナビゲーションは、「前へ」/「次へ」ボタンまたは矢印キーを使用して行います。完了したら、[すべてのレビューを送信] をクリックすると、すべてのフィードバックがfeedback.jsonに保存されます。
ステップ 5: フィードバックを読む
ユーザーが完了したと言ったら、feedback.jsonを読みます。
{
"reviews": [
{"run_id": "eval-0-with_skill", "feedback": "the chart is missing axis labels", "timestamp": "..."},
{"run_id": "eval-1-with_skill", "feedback": "", "timestamp": "..."},
{"run_id": "eval-2-with_skill", "feedback": "perfect, love this", "timestamp": "..."}
],
"status": "complete"
}空のフィードバックは、ユーザーが問題ないと判断したことを意味します。ユーザーから特定の苦情があったテスト ケースに焦点を当てて改善します。
作業が終わったら、ビューア サーバーを強制終了します。
kill $VIEWER_PID 2>/dev/nullスキルの向上
これがループの中心です。テスト ケースを実行し、ユーザーが結果をレビューしたら、フィードバックに基づいてスキルを改善する必要があります。
改善をどう考えるか
-
フィードバックから一般化します。 ここで起こっている全体像は、多くの異なるプロンプトにわたって何百万回も (おそらく文字通り、もしかしたら知っている人はもっと多く) 使用できるスキルを作成しようとしているということです。ここでは、あなたとユーザーは、より速く進むのに役立つため、少数の例だけを何度も繰り返しています。ユーザーはこれらの例を隅々まで知っているので、新しい出力をすぐに評価できます。しかし、あなたとユーザーが共同開発しているスキルがそれらの例でのみ機能する場合、それは役に立ちません。頑固な問題がある場合は、面倒な過剰適合の変更や抑圧的な制限を加えるのではなく、分岐して別の比喩を使用したり、別の作業パターンを推奨したりすることもできます。比較的安価に試せるので、素晴らしいものが見つかるかもしれません。
-
プロンプトを無駄のない状態に保ちます。 重量を支えていないものは取り除きます。最終出力だけでなく、必ずトランスクリプトを読んでください。スキルがモデルに非生産的なことを行うために多くの時間を無駄にさせているように見える場合は、そのような動作をさせているスキルの部分を削除して、何が起こるかを確認してみてください。
-
理由を説明してください。 モデルに要求しているすべての背後にある 理由 を一生懸命説明してください。今日の LLM は * 賢い * です。彼らは優れた精神理論を持っており、優れたハーネスを与えられると、暗記的な指示を超えて実際に物事を実現することができます。ユーザーからのフィードバックが簡潔であったりイライラしたりする場合でも、タスクとユーザーが書いたものをなぜ書いているのか、そして実際に何を書いたのかを実際に理解するよう努め、その理解を指示に反映させてください。 ALWAYS または NEVER をすべて大文字で書いたり、非常に厳格な構造を使用したりしていることに気付いた場合、それは黄色の旗です。可能であれば、求めているものがなぜ重要であるかをモデルが理解できるように、推論を再構築して説明してください。それはより人道的で強力かつ効果的なアプローチです。
-
テスト ケース全体で繰り返される作業を探します。 テスト実行のトランスクリプトを読み、サブエージェントがすべて個別に同様のヘルパー スクリプトを作成していないか、何かに対して同じ複数ステップのアプローチをとっていないかを確認します。 3 つのテスト ケースすべての結果、サブエージェントが
create_docx.pyまたはbuild_chart.pyを作成した場合、それはスキルがそのスクリプトをバンドルする必要があるという強力なシグナルです。一度書いてscripts/に入れて、それを使用するようにスキルに指示します。これにより、今後のすべての呼び出しで車輪の再発明が不要になります。
このタスクは非常に重要であり (私たちはここで年間数十億ドルの経済価値を生み出そうとしています!)、思考時間は妨げにはなりません。時間をかけて本当によく考えてください。改訂草案を書いてから、もう一度見直して改善することをお勧めします。ユーザーの頭の中に入り込み、彼らが何を望んでいるのか、何を必要としているのかを理解するために最善を尽くしてください。
反復ループ
スキルを向上させた後:
- 改善をスキルに適用する
- ベースライン実行を含むすべてのテスト ケースを新しい
iteration-<N+1>/ディレクトリで再実行します。新しいスキルを作成する場合、ベースラインは常にwithout_skill(スキルなし) であり、これは繰り返しを通じて同じままです。既存のスキルを改善する場合は、ベースラインとして何が合理的かを判断してください。つまり、ユーザーが使用した元のバージョン、または前回のイテレーションです。 - 前のイテレーションを指す
--previous-workspaceでレビューアを起動します - ユーザーが確認して完了したと伝えるまで待ちます
- 新しいフィードバックを読んで、再度改善し、繰り返します
次の状態になるまで続けます。
- ユーザーは満足していると言っています
- フィードバックはすべて空です (すべてが良好に見えます)
- 有意義な進歩を遂げていない
上級: ブラインド比較
スキルの 2 つのバージョンをより厳密に比較したい場合 (例: ユーザーが「新しいバージョンのほうが実際に優れているのですか?」と尋ねた場合)、ブラインド比較システムがあります。詳細については、agents/comparator.mdおよびagents/analyzer.mdをお読みください。基本的な考え方は、独立したエージェントに 2 つの出力をどちらであるかを伝えずに与え、品質を判断させるというものです。次に、勝者が勝った理由を分析します。
これはオプションであり、サブエージェントが必要ですが、ほとんどのユーザーには必要ありません。通常は人間によるレビュー ループで十分です。
説明の最適化
SKILL.md フロントマターの説明フィールドは、クロードがスキルを呼び出すかどうかを決定する主要なメカニズムです。スキルを作成または改善した後、トリガーの精度を高めるために説明を最適化することを提案します。
ステップ 1: トリガー評価クエリを生成する
トリガーすべきクエリとトリガーすべきでないクエリを組み合わせた 20 個の評価クエリを作成します。 JSON として保存:
[
{"query": "the user prompt", "should_trigger": true},
{"query": "another prompt", "should_trigger": false}
]クエリは現実的で、Claude Code または Claude.ai ユーザーが実際に入力するものでなければなりません。抽象的なリクエストではなく、具体的かつ詳細なリクエストです。たとえば、ファイル パス、ユーザーの仕事や状況に関する個人的なコンテキスト、列の名前と値、会社名、URL などです。ちょっとした裏話。一部は小文字であったり、略語、タイプミス、カジュアルな話し言葉が含まれている場合があります。さまざまな長さを組み合わせて使用し、明確にするのではなく、特殊なケースに焦点を当てます (ユーザーが承認する機会が得られます)。
悪い:"Format this data"、"Extract text from PDF"、"Create a chart"
良い:"ok so my boss just sent me this xlsx file (its in my downloads, called something like 'Q4 sales final FINAL v2.xlsx') and she wants me to add a column that shows the profit margin as a percentage. The revenue is in column C and costs are in column D i think"
トリガーすべき クエリ (8 ~ 10) については、カバレッジについて考えてください。同じ意図でも、フォーマルな表現やカジュアルな表現など、さまざまな表現が必要になります。ユーザーがスキルやファイルの種類を明示的に指定していないが、明らかにそれが必要である場合も含めます。いくつかの珍しいユースケースや、このスキルが別のスキルと競合するものの、勝つ必要があるケースを考慮します。
トリガーすべきではない クエリ (8 ~ 10) の場合、最も価値のあるものはニアミス、つまりスキルとキーワードやコンセプトを共有しているが、実際には別のものを必要とするクエリです。隣接するドメイン、単純なキーワード一致がトリガーされるはずなのにトリガーされるべきではない曖昧な表現、クエリがスキルの実行内容に触れているが、別のツールの方が適切なコンテキストである場合を考えてください。
避けるべき重要なことは、トリガーすべきではないクエリを明らかに無関係なものにしないことです。 PDF スキルの否定テストとして「フィボナッチ関数を書く」というのは簡単すぎます。何もテストされていません。否定的なケースは本当に注意が必要です。
ステップ 2: ユーザーによるレビュー
HTML テンプレートを使用して、レビューのために評価セットをユーザーに提示します。
assets/eval_review.htmlからテンプレートを読み取る- プレースホルダーを置き換えます。
__EVAL_DATA_PLACEHOLDER__-> eval 項目の JSON 配列 (引用符で囲まない - これは JS 変数の割り当てです)__SKILL_NAME_PLACEHOLDER__-> スキルの名前__SKILL_DESCRIPTION_PLACEHOLDER__-> スキルの現在の説明
- 一時ファイル (例:
/tmp/eval_review_<skill-name>.html) に書き込み、それを開きます:open /tmp/eval_review_<skill-name>.html - ユーザーはクエリを編集し、トリガーの切り替え、エントリの追加/削除を行ってから、[評価セットのエクスポート] をクリックします。
- ファイルは
~/Downloads/eval_set.jsonにダウンロードされます。複数のバージョンがある場合は、ダウンロード フォルダーで最新バージョンを確認してください (例:eval_set (1).json)。
このステップは重要です。不適切な eval クエリは不適切な記述につながります。
ステップ 3: 最適化ループを実行する
ユーザーに「これには時間がかかります。バックグラウンドで最適化ループを実行し、定期的にチェックします。」と伝えます。
評価セットをワークスペースに保存し、バックグラウンドで実行します。
python -m scripts.run_loop \
--eval-set <path-to-trigger-eval.json> \
--skill-path <path-to-skill> \
--model <model-id-powering-this-session> \
--max-iterations 5 \
--verboseシステム プロンプト (現在のセッションに電力を供給するもの) のモデル ID を使用して、トリガーとなるテストがユーザーが実際に経験するものと一致するようにします。
実行中、定期的に出力を追跡して、どの反復が実行されているか、およびスコアがどのようになっているかに関する最新情報をユーザーに提供します。
これにより、完全な最適化ループが自動的に処理されます。評価セットを 60% のトレーニングと 40% のホールドアウト テストに分割し、現在の説明を評価し (信頼できるトリガー レートを取得するために各クエリを 3 回実行します)、次に Claude を呼び出して失敗した内容に基づいて改善を提案します。トレーニングとテストの両方で新しい記述をそれぞれ再評価し、最大 5 回繰り返します。完了すると、ブラウザーで HTML レポートが開き、反復ごとの結果が表示され、過剰適合を避けるためにトレーニング スコアではなくテスト スコアによって選択されたbest_descriptionを含む JSON が返されます。
スキル発動の仕組み
トリガーのメカニズムを理解すると、より適切な eval クエリを設計するのに役立ちます。スキルはクロードのavailable_skillsリストに名前と説明とともに表示され、クロードはその説明に基づいてスキルを参照するかどうかを決定します。知っておくべき重要な点は、クロードが単独で簡単に処理できないタスクのスキルのみを参照するということです。クロードは基本的なツールで直接処理できるため、「この PDF を読んでください」などの単純なワンステップ クエリは、説明が完全に一致していてもスキルをトリガーしない可能性があります。複雑なクエリ、複数ステップのクエリ、または特殊なクエリは、説明が一致すると確実にスキルをトリガーします。
つまり、評価クエリは、クロードがスキルを参照することで実際に利益を得ることができるほど実質的なものである必要があります。 「ファイル X を読み取る」などの単純なクエリはテスト ケースとしては不十分です。記述の品質に関係なく、スキルはトリガーされません。
ステップ 4: 結果を適用する
JSON 出力からbest_descriptionを取得し、スキルの SKILL.md フロントマターを更新します。ユーザーにビフォー/アフターを表示し、スコアを報告します。
パッケージとプレゼント (present_filesツールが利用可能な場合のみ)
present_filesツールにアクセスできるかどうかを確認してください。そうでない場合は、この手順をスキップしてください。その場合は、スキルをパッケージ化し、.skill ファイルをユーザーに提示します。
python -m scripts.package_skill <path/to/skill-folder>パッケージ化後、ユーザーがインストールできるように、生成された.skillファイル パスに誘導します。
Claude.ai 固有の手順
Claude.ai では、コアのワークフローは同じ (ドラフト -> テスト -> レビュー -> 改善 -> 繰り返し) ですが、Claude.ai にはサブエージェントがないため、一部の仕組みが変わります。適応すべきものは次のとおりです。
テスト ケースの実行: サブエージェントがないということは、並列実行がないことを意味します。各テスト ケースについて、スキルの SKILL.md を読み、その指示に従ってテスト プロンプトを自分で実行します。それらを一度に 1 つずつ実行してください。これは、独立したサブエージェントほど厳密ではありません (スキルを作成し、それを実行しているため、完全なコンテキストが得られます) が、健全性チェックとしては有用であり、人間によるレビュー手順で補われます。ベースラインの実行をスキップし、スキルを使用して要求に応じてタスクを完了するだけです。
結果のレビュー: ブラウザを開けない場合 (例: Claude.ai の VM にディスプレイがない、またはリモート サーバー上にある)、ブラウザ レビューアを完全にスキップしてください。代わりに、会話の中で結果を直接提示してください。各テスト ケースについて、プロンプトと出力を表示します。出力がユーザーに表示する必要があるファイル (.docx や.xlsx など) の場合は、それをファイル システムに保存し、ダウンロードして検査できるように場所を伝えます。インラインでフィードバックを求めます:「これはどうですか? 変更したい点はありますか?」
ベンチマーク: 定量的なベンチマークは省略します。ベースライン比較に依存しますが、サブエージェントがなければ意味がありません。ユーザーからの定性的なフィードバックに重点を置きます。
反復ループ: 以前と同じ - スキルを向上させ、テスト ケースを再実行し、フィードバックを求めます - 間にブラウザーのレビュー担当者がいないだけです。ファイルシステム上に反復ディレクトリがある場合は、そのディレクトリに結果を整理できます。
説明の最適化: このセクションでは、Claude Code でのみ使用できるclaudeCLI ツール (具体的にはclaude -p) が必要です。 Claude.ai を使用している場合はスキップしてください。
ブラインド比較: サブエージェントが必要です。スキップしてください。
パッケージング:package_skill.pyスクリプトは、Python とファイルシステムがあればどこでも動作します。 Claude.ai では、これを実行し、ユーザーは結果の.skillファイルをダウンロードできます。
既存のスキルの更新: ユーザーは、新しいスキルを作成するのではなく、既存のスキルを更新するように求めている可能性があります。この場合:
- 元の名前を保持します。 スキルのディレクトリ名と
nameフロントマター フィールドに注意してください -- 変更せずに使用してください。たとえば、インストールされているスキルがresearch-helperの場合、research-helper.skill(research-helper-v2ではありません) を出力します。 - 編集する前に書き込み可能な場所にコピーしてください。 インストールされたスキル パスは読み取り専用である可能性があります。
/tmp/skill-name/にコピーし、そこで編集し、コピーからパッケージ化します。 - 手動でパッケージ化する場合は、最初に
/tmp/にステージングしてから、次に出力ディレクトリにコピーします -- 権限が原因で直接書き込みが失敗する可能性があります。
Cowork 固有の指示
Cowork を使用している場合、主に知っておくべきことは次のとおりです。
- サブエージェントがあるため、メインのワークフロー (テスト ケースの並行生成、ベースラインの実行、評価など) がすべて機能します。 (ただし、タイムアウトに関する重大な問題が発生した場合は、テスト プロンプトを並列ではなく直列で実行しても問題ありません。)
- ブラウザやディスプレイがないため、eval ビューアを生成するときは、サーバーを起動する代わりに、
--static <output_path>を使用してスタンドアロン HTML ファイルを作成します。次に、ユーザーがクリックしてブラウザーで HTML を開くことができるリンクを提供します。 - 何らかの理由で、Cowork の設定では、Claude がテスト実行後に eval ビューアを生成することを拒否しているようです。そのため、繰り返します: Cowork であろうと Claude Code であろうと、テスト実行後は、
generate_review.pyを使用して (独自のブティック HTML コードを作成するのではなく) スキルを自分で改訂して修正を試みる前に、人間がサンプルを参照できるように常に eval ビューアを生成する必要があります。事前に申し訳ありませんが、ここではすべて大文字で説明します: 入力を自分で評価する 前 に評価ビューアを生成します。できるだけ早く人間の前に彼らを連れて行きたいです! - フィードバックの動作は異なります。実行中のサーバーがないため、ビューアの [すべてのレビューを送信] ボタンは
feedback.jsonをファイルとしてダウンロードします。その後、そこから読み取ることができます (最初にアクセスをリクエストする必要がある場合があります)。 - パッケージ化は機能します -
package_skill.pyに必要なのは Python とファイルシステムだけです。 - 説明の最適化 (
run_loop.py/run_eval.py) はブラウザではなくサブプロセス経由でclaude -pを使用するため、Cowork では問題なく動作するはずですが、スキルの作成が完全に完了し、ユーザーが良好な状態であることに同意するまで保存してください。 - 既存のスキルの更新: ユーザーは、新しいスキルを作成するのではなく、既存のスキルを更新するように求めている可能性があります。上記の claude.ai セクションの更新ガイダンスに従ってください。
参照ファイル
Agents/ ディレクトリには、特殊なサブエージェントの手順が含まれています。関連するサブエージェントを生成する必要がある場合に読んでください。
agents/grader.md- 出力に対してアサーションを評価する方法agents/comparator.md- 2 つの出力間でブラインド A/B 比較を行う方法agents/analyzer.md- あるバージョンが別のバージョンに勝る理由を分析する方法
References/ ディレクトリには追加のドキュメントがあります。
references/schemas.md- evals.json、grading.json などの JSON 構造。
強調するために、ここでコア ループをもう一度繰り返します。
- スキルの内容を理解する
- スキルの下書きまたは編集
- テストプロンプトで claude-with-access-to-the-skill を実行します
- ユーザーと一緒に出力を評価します。
- ユーザーがベンチマークを確認できるように、benchmark.json を作成し、
eval-viewer/generate_review.pyを実行します。 - 定量的評価を実行する
- ユーザーがベンチマークを確認できるように、benchmark.json を作成し、
- あなたとユーザーが満足するまで繰り返します
- 最終的なスキルをパッケージ化してユーザーに返します。
そのようなものがある場合は、忘れないように TodoList にステップを追加してください。 Cowork を使用している場合は、それが確実に行われるように、TodoList に「evals JSON を作成してeval-viewer/generate_review.pyを実行して人間がテスト ケースをレビューできるようにする」と具体的に入れてください。
頑張ってください!
リソースファイル
ライセンス.txt
バイナリリソース
エージェント/アナライザー.md
バイナリリソース
エージェント/comparator.md
バイナリリソース
エージェント/グレーダー.md
バイナリリソース
アセット/eval_review.html
assets/eval_review.html をダウンロード
バイナリリソース
eval-viewer/generate_review.py
eval-viewer/generate_review.py をダウンロード
バイナリリソース
eval-viewer/viewer.html
eval-viewer/viewer.html をダウンロード
バイナリリソース
参照/schemas.md
バイナリリソース
スクリプト/init.py
バイナリリソース
scripts/aggregate_benchmark.py
スクリプトをダウンロード/aggregate_benchmark.py
バイナリリソース
スクリプト/generate_report.py
スクリプトをダウンロード/generate_report.py
バイナリリソース
scripts/improve_description.py
スクリプトをダウンロード/improve_description.py
バイナリリソース
スクリプト/package_skill.py
#!/usr/bin/env python3
"""
Skill Packager - Creates a distributable .skill file of a skill folder
Usage:
python utils/package_skill.py <path/to/skill-folder> [output-directory]
Example:
python utils/package_skill.py skills/public/my-skill
python utils/package_skill.py skills/public/my-skill ./dist
"""
import fnmatch
import sys
import zipfile
from pathlib import Path
from scripts.quick_validate import validate_skill
# Patterns to exclude when packaging skills.
EXCLUDE_DIRS = {"__pycache__", "node_modules"}
EXCLUDE_GLOBS = {"*.pyc"}
EXCLUDE_FILES = {".DS_Store"}
# Directories excluded only at the skill root (not when nested deeper).
ROOT_EXCLUDE_DIRS = {"evals"}
def should_exclude(rel_path: Path) -> bool:
"""Check if a path should be excluded from packaging."""
parts = rel_path.parts
if any(part in EXCLUDE_DIRS for part in parts):
return True
# rel_path is relative to skill_path.parent, so parts[0] is the skill
# folder name and parts[1] (if present) is the first subdir.
if len(parts) > 1 and parts[1] in ROOT_EXCLUDE_DIRS:
return True
name = rel_path.name
if name in EXCLUDE_FILES:
return True
return any(fnmatch.fnmatch(name, pat) for pat in EXCLUDE_GLOBS)
def package_skill(skill_path, output_dir=None):
"""
Package a skill folder into a .skill file.
Args:
skill_path: Path to the skill folder
output_dir: Optional output directory for the .skill file (defaults to current directory)
Returns:
Path to the created .skill file, or None if error
"""
skill_path = Path(skill_path).resolve()
# Validate skill folder exists
if not skill_path.exists():
print(f"❌ Error: Skill folder not found: {skill_path}")
return None
if not skill_path.is_dir():
print(f"❌ Error: Path is not a directory: {skill_path}")
return None
# Validate SKILL.md exists
skill_md = skill_path / "SKILL.md"
if not skill_md.exists():
print(f"❌ Error: SKILL.md not found in {skill_path}")
return None
# Run validation before packaging
print("🔍 Validating skill...")
valid, message = validate_skill(skill_path)
if not valid:
print(f"❌ Validation failed: {message}")
print(" Please fix the validation errors before packaging.")
return None
print(f"✅ {message}\n")
# Determine output location
skill_name = skill_path.name
if output_dir:
output_path = Path(output_dir).resolve()
output_path.mkdir(parents=True, exist_ok=True)
else:
output_path = Path.cwd()
skill_filename = output_path / f"{skill_name}.skill"
# Create the .skill file (zip format)
try:
with zipfile.ZipFile(skill_filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
# Walk through the skill directory, excluding build artifacts
for file_path in skill_path.rglob('*'):
if not file_path.is_file():
continue
arcname = file_path.relative_to(skill_path.parent)
if should_exclude(arcname):
print(f" Skipped: {arcname}")
continue
zipf.write(file_path, arcname)
print(f" Added: {arcname}")
print(f"\n✅ Successfully packaged skill to: {skill_filename}")
return skill_filename
except Exception as e:
print(f"❌ Error creating .skill file: {e}")
return None
def main():
if len(sys.argv) < 2:
print("Usage: python utils/package_skill.py <path/to/skill-folder> [output-directory]")
print("\nExample:")
print(" python utils/package_skill.py skills/public/my-skill")
print(" python utils/package_skill.py skills/public/my-skill ./dist")
sys.exit(1)
skill_path = sys.argv[1]
output_dir = sys.argv[2] if len(sys.argv) > 2 else None
print(f"📦 Packaging skill: {skill_path}")
if output_dir:
print(f" Output directory: {output_dir}")
print()
result = package_skill(skill_path, output_dir)
if result:
sys.exit(0)
else:
sys.exit(1)
if __name__ == "__main__":
main()スクリプト/quick_validate.py
スクリプトをダウンロード/quick_validate.py
#!/usr/bin/env python3
"""
Quick validation script for skills - minimal version
"""
import sys
import os
import re
import yaml
from pathlib import Path
def validate_skill(skill_path):
"""Basic validation of a skill"""
skill_path = Path(skill_path)
# Check SKILL.md exists
skill_md = skill_path / 'SKILL.md'
if not skill_md.exists():
return False, "SKILL.md not found"
# Read and validate frontmatter
content = skill_md.read_text()
if not content.startswith('---'):
return False, "No YAML frontmatter found"
# Extract frontmatter
match = re.match(r'^---\n(.*?)\n---', content, re.DOTALL)
if not match:
return False, "Invalid frontmatter format"
frontmatter_text = match.group(1)
# Parse YAML frontmatter
try:
frontmatter = yaml.safe_load(frontmatter_text)
if not isinstance(frontmatter, dict):
return False, "Frontmatter must be a YAML dictionary"
except yaml.YAMLError as e:
return False, f"Invalid YAML in frontmatter: {e}"
# Define allowed properties
ALLOWED_PROPERTIES = {'name', 'description', 'license', 'allowed-tools', 'metadata', 'compatibility'}
# Check for unexpected properties (excluding nested keys under metadata)
unexpected_keys = set(frontmatter.keys()) - ALLOWED_PROPERTIES
if unexpected_keys:
return False, (
f"Unexpected key(s) in SKILL.md frontmatter: {', '.join(sorted(unexpected_keys))}. "
f"Allowed properties are: {', '.join(sorted(ALLOWED_PROPERTIES))}"
)
# Check required fields
if 'name' not in frontmatter:
return False, "Missing 'name' in frontmatter"
if 'description' not in frontmatter:
return False, "Missing 'description' in frontmatter"
# Extract name for validation
name = frontmatter.get('name', '')
if not isinstance(name, str):
return False, f"Name must be a string, got {type(name).__name__}"
name = name.strip()
if name:
# Check naming convention (kebab-case: lowercase with hyphens)
if not re.match(r'^[a-z0-9-]+$', name):
return False, f"Name '{name}' should be kebab-case (lowercase letters, digits, and hyphens only)"
if name.startswith('-') or name.endswith('-') or '--' in name:
return False, f"Name '{name}' cannot start/end with hyphen or contain consecutive hyphens"
# Check name length (max 64 characters per spec)
if len(name) > 64:
return False, f"Name is too long ({len(name)} characters). Maximum is 64 characters."
# Extract and validate description
description = frontmatter.get('description', '')
if not isinstance(description, str):
return False, f"Description must be a string, got {type(description).__name__}"
description = description.strip()
if description:
# Check for angle brackets
if '<' in description or '>' in description:
return False, "Description cannot contain angle brackets (< or >)"
# Check description length (max 1024 characters per spec)
if len(description) > 1024:
return False, f"Description is too long ({len(description)} characters). Maximum is 1024 characters."
# Validate compatibility field if present (optional)
compatibility = frontmatter.get('compatibility', '')
if compatibility:
if not isinstance(compatibility, str):
return False, f"Compatibility must be a string, got {type(compatibility).__name__}"
if len(compatibility) > 500:
return False, f"Compatibility is too long ({len(compatibility)} characters). Maximum is 500 characters."
return True, "Skill is valid!"
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python quick_validate.py <skill_directory>")
sys.exit(1)
valid, message = validate_skill(sys.argv[1])
print(message)
sys.exit(0 if valid else 1)スクリプト/run_eval.py
バイナリリソース
スクリプト/run_loop.py
バイナリリソース
スクリプト/utils.py
"""Shared utilities for skill-creator scripts."""
from pathlib import Path
def parse_skill_md(skill_path: Path) -> tuple[str, str, str]:
"""Parse a SKILL.md file, returning (name, description, full_content)."""
content = (skill_path / "SKILL.md").read_text()
lines = content.split("\n")
if lines[0].strip() != "---":
raise ValueError("SKILL.md missing frontmatter (no opening ---)")
end_idx = None
for i, line in enumerate(lines[1:], start=1):
if line.strip() == "---":
end_idx = i
break
if end_idx is None:
raise ValueError("SKILL.md missing frontmatter (no closing ---)")
name = ""
description = ""
frontmatter_lines = lines[1:end_idx]
i = 0
while i < len(frontmatter_lines):
line = frontmatter_lines[i]
if line.startswith("name:"):
name = line[len("name:"):].strip().strip('"').strip("'")
elif line.startswith("description:"):
value = line[len("description:"):].strip()
# Handle YAML multiline indicators (>, |, >-, |-)
if value in (">", "|", ">-", "|-"):
continuation_lines: list[str] = []
i += 1
while i < len(frontmatter_lines) and (frontmatter_lines[i].startswith(" ") or frontmatter_lines[i].startswith("\t")):
continuation_lines.append(frontmatter_lines[i].strip())
i += 1
description = " ".join(continuation_lines)
continue
else:
description = value.strip('"').strip("'")
i += 1
return name, description, content
クロードスキルのドキュメント