Browse documentation

Source reviewed8a1541c4a3ff

スキルクリエイター

スクリプト、リファレンス、アセットを備えた再利用可能なスキルの範囲設定、構造化、パッケージ化に関するエージェント スキルのライフサイクル ガイド。

Anthropic · Skill Creator

Existing editorial guidance is preserved. The current pinned official reference is separately labelled in English; translated editorial is not a new translation of the full source.

This is the existing editorial translation. The latest full official reference, where available, is provided separately in English.

The navigation uses English labels. Article languages are shown separately; the interface is not a full translation of the documentation.

Source text is documentation. These workflows have not been executed or tested by this site.

On this page

新しいスキルを作成し、繰り返し改善するためのスキル。

大まかに言うと、スキルを作成するプロセスは次のようになります。

  • スキルに何をさせたいのか、そしてそれをどのように行うべきかを大まかに決定します
  • スキルの下書きを書く
  • いくつかのテスト プロンプトを作成し、それらに対して claude-with-access-to-the-skill を実行します。
  • ユーザーが結果を定性的および定量的に評価できるようにする
    • 実行がバックグラウンドで行われている間に、定量的評価が存在しない場合はドラフトを作成します (存在する場合は、そのまま使用することも、何かを変更する必要があると感じた場合は変更することもできます)。次に、それらをユーザーに説明します (または、すでに存在する場合は、すでに存在するものについて説明します)。
    • eval-viewer/generate_review.pyスクリプトを使用して、ユーザーに確認できる結果を表示し、定量的な指標も確認できるようにします。
  • 結果に対するユーザーの評価からのフィードバックに基づいてスキルを書き直します (また、定量的なベンチマークから明らかになった明らかな欠陥がある場合も同様です)。
  • 満足するまで繰り返します
  • テスト セットを拡張して、より大規模な規模で再試行してください

このスキルを使用するときの仕事は、ユーザーがこのプロセスのどの段階にいるのかを把握し、そこに飛び込み、これらの段階を進んでいくのを支援することです。たとえば、「X のスキルを作りたい」というようなことかもしれません。意味を絞り込み、下書きを書き、テスト ケースを書き、どのように評価するかを考え、すべてのプロンプトを実行し、それを繰り返すことができます。

一方で、もしかしたらすでにスキルの草案を持っているかもしれません。この場合、ループの評価/反復部分に直接進むことができます。

もちろん、常に柔軟である必要があります。ユーザーが「たくさんの評価を実行する必要はない、ただ一緒にいてほしい」という場合は、代わりにそうすることができます。

次に、スキルが完了した後 (ただし、順序は柔軟です)、スキルのトリガーを最適化するために、完全に別のスクリプトが用意されているスキル記述改善プログラムを実行することもできます。

かっこいい?いいね。

ユーザーとのコミュニケーション

スキル クリエーターは、コーディング専門用語に精通した幅広い人々によって使用される可能性があります。聞いたことがない方のために説明します (そして、どうしてわかるでしょうか。それが始まったのはごく最近のことです)。現在、クロードの力によって配管工が端末を開放し、親や祖父母が「npm のインストール方法」をグーグルで検索するようになっている傾向があります。一方で、ユーザーの大部分はおそらくかなりコンピューターに精通しています。

したがって、コミュニケーションの表現方法を理解するために、文脈の手がかりに注意を払ってください。デフォルトの場合は、次のようになります。

  • 「評価」と「ベンチマーク」は境界線だけどOK
  • 「JSON」と「アサーション」については、ユーザーが説明せずに使用する前に、それらが何であるかを知っているという真剣な合図が必要です。

疑問がある場合は用語を簡単に説明しても問題ありません。ユーザーが理解できるかどうかわからない場合は、短い定義で用語を明確にしてもかまいません。


スキルの作成

意図のキャプチャ

まずはユーザーの意図を理解することから始めましょう。現在の会話には、ユーザーがキャプチャしたいワークフローがすでに含まれている可能性があります (例: 「これをスキルに変える」など)。その場合は、まず会話履歴から、使用したツール、一連の手順、ユーザーが行った修正、観察された入力/出力形式などの回答を抽出します。ユーザーはギャップを埋める必要がある場合があるため、次のステップに進む前に確認する必要があります。

  1. クロードはこのスキルで何をできるようになるでしょうか?
  2. このスキルはいつ発動するべきですか? (ユーザーのフレーズ/コンテキスト)
  3. 予想される出力形式は何ですか?
  4. スキルが機能することを確認するためにテストケースを設定する必要がありますか?客観的に検証可能な出力 (ファイル変換、データ抽出、コード生成、固定ワークフロー ステップ) を備えたスキルは、テスト ケースから恩恵を受けます。主観的なアウトプット(文体、芸術)を伴うスキルには、多くの場合、それらは必要ありません。スキルのタイプに基づいて適切なデフォルトを提案しますが、決定はユーザーに任せます。

インタビューと調査

特殊なケース、入出力形式、サンプル ファイル、成功基準、依存関係について積極的に質問してください。この部分が解決されるまで、テスト プロンプトを作成するのを待ちます。

利用可能な 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 レベルのロード システムが使用されます。

  1. メタデータ (名前 + 説明) - 常にコンテキスト内にあります (~100 ワード)
  2. SKILL.md body - スキルがトリガーされるたびにコンテキスト内に表示されます (500 行未満が理想的)
  3. バンドルされたリソース - 必要に応じて (無制限、スクリプトはロードせずに実行可能)

これらの単語数はおおよそのものであり、必要に応じてさらに長くしても構いません。

主なパターン:

  • 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 &lt;skill-path&gt; &lt;workspace&gt;/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: 採点、集計、ビューアの起動

すべての実行が完了したら、次のようにします。

  1. 各実行を採点 -agents/grader.mdを読み取り、出力に対して各アサーションを評価する採点サブエージェント (またはインラインで採点) を生成します。結果を各実行ディレクトリのgrading.jsonに保存します。 grading.json の期待配列では、フィールドtext、passed、およびevidence(name/met/detailsまたはその他のバリアントではない) を使用する必要があります。ビューアーはこれらの正確なフィールド名に依存します。プログラムでチェックできるアサーションの場合は、スクリプトを目視するのではなく、スクリプトを作成して実行します。スクリプトはより高速で信頼性が高く、反復間で再利用できます。

  2. ベンチマークに集約 - スキル作成者ディレクトリから集約スクリプトを実行します。

    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 バージョンを、対応するベースラインバージョンの前に置きます。

  3. アナリスト パスを実行します - ベンチマーク データと、集計統計に隠れている可能性のある表面パターンを読み取ります。何を探すべきかについては、agents/analyzer.md(「ベンチマーク結果の分析」セクション) を参照してください。スキルに関係なく常に合格するアサーション (無差別)、分散の高い eval (不安定な可能性がある)、時間とトークンのトレードオフなどです。

  4. ビューアを起動して、定性的な出力と定量的なデータの両方を表示します。

    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 &lt;workspace&gt;/iteration-&lt;N-1&gt;も渡します。

    コワーク/ヘッドレス環境:webbrowser.open()が使用できない場合、または環境にディスプレイがない場合は、サーバーを起動する代わりに、--static &lt;output_path&gt;を使用してスタンドアロン HTML ファイルを作成します。ユーザーが「すべてのレビューを送信」をクリックすると、フィードバックはfeedback.jsonファイルとしてダウンロードされます。ダウンロード後、次の反復で取得できるように、feedback.jsonをワークスペース ディレクトリにコピーします。

注: ビューアを作成するには、generate_review.py を使用してください。カスタム HTML を記述する必要はありません。

  1. ユーザーに次のようなことを伝えます: 「ブラウザで結果を開いたところです。タブが 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

スキルの向上

これがループの中心です。テスト ケースを実行し、ユーザーが結果をレビューしたら、フィードバックに基づいてスキルを改善する必要があります。

改善をどう考えるか

  1. フィードバックから一般化します。 ここで起こっている全体像は、多くの異なるプロンプトにわたって何百万回も (おそらく文字通り、もしかしたら知っている人はもっと多く) 使用できるスキルを作成しようとしているということです。ここでは、あなたとユーザーは、より速く進むのに役立つため、少数の例だけを何度も繰り返しています。ユーザーはこれらの例を隅々まで知っているので、新しい出力をすぐに評価できます。しかし、あなたとユーザーが共同開発しているスキルがそれらの例でのみ機能する場合、それは役に立ちません。頑固な問題がある場合は、面倒な過剰適合の変更や抑圧的な制限を加えるのではなく、分岐して別の比喩を使用したり、別の作業パターンを推奨したりすることもできます。比較的安価に試せるので、素晴らしいものが見つかるかもしれません。

  2. プロンプトを無駄のない状態に保ちます。 重量を支えていないものは取り除きます。最終出力だけでなく、必ずトランスクリプトを読んでください。スキルがモデルに非生産的なことを行うために多くの時間を無駄にさせているように見える場合は、そのような動作をさせているスキルの部分を削除して、何が起こるかを確認してみてください。

  3. 理由を説明してください。 モデルに要求しているすべての背後にある 理由 を一生懸命説明してください。今日の LLM は * 賢い * です。彼らは優れた精神理論を持っており、優れたハーネスを与えられると、暗記的な指示を超えて実際に物事を実現することができます。ユーザーからのフィードバックが簡潔であったりイライラしたりする場合でも、タスクとユーザーが書いたものをなぜ書いているのか、そして実際に何を書いたのかを実際に理解するよう努め、その理解を指示に反映させてください。 ALWAYS または NEVER をすべて大文字で書いたり、非常に厳格な構造を使用したりしていることに気付いた場合、それは黄色の旗です。可能であれば、求めているものがなぜ重要であるかをモデルが理解できるように、推論を再構築して説明してください。それはより人道的で強力かつ効果的なアプローチです。

  4. テスト ケース全体で繰り返される作業を探します。 テスト実行のトランスクリプトを読み、サブエージェントがすべて個別に同様のヘルパー スクリプトを作成していないか、何かに対して同じ複数ステップのアプローチをとっていないかを確認します。 3 つのテスト ケースすべての結果、サブエージェントがcreate_docx.pyまたはbuild_chart.pyを作成した場合、それはスキルがそのスクリプトをバンドルする必要があるという強力なシグナルです。一度書いてscripts/に入れて、それを使用するようにスキルに指示します。これにより、今後のすべての呼び出しで車輪の再発明が不要になります。

このタスクは非常に重要であり (私たちはここで年間数十億ドルの経済価値を生み出そうとしています!)、思考時間は妨げにはなりません。時間をかけて本当によく考えてください。改訂草案を書いてから、もう一度見直して改善することをお勧めします。ユーザーの頭の中に入り込み、彼らが何を望んでいるのか、何を必要としているのかを理解するために最善を尽くしてください。

反復ループ

スキルを向上させた後:

  1. 改善をスキルに適用する
  2. ベースライン実行を含むすべてのテスト ケースを新しいiteration-&lt;N+1&gt;/ディレクトリで再実行します。新しいスキルを作成する場合、ベースラインは常にwithout_skill(スキルなし) であり、これは繰り返しを通じて同じままです。既存のスキルを改善する場合は、ベースラインとして何が合理的かを判断してください。つまり、ユーザーが使用した元のバージョン、または前回のイテレーションです。
  3. 前のイテレーションを指す--previous-workspaceでレビューアを起動します
  4. ユーザーが確認して完了したと伝えるまで待ちます
  5. 新しいフィードバックを読んで、再度改善し、繰り返します

次の状態になるまで続けます。

  • ユーザーは満足していると言っています
  • フィードバックはすべて空です (すべてが良好に見えます)
  • 有意義な進歩を遂げていない

上級: ブラインド比較

スキルの 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 テンプレートを使用して、レビューのために評価セットをユーザーに提示します。

  1. assets/eval_review.htmlからテンプレートを読み取る
  2. プレースホルダーを置き換えます。
    • __EVAL_DATA_PLACEHOLDER__-> eval 項目の JSON 配列 (引用符で囲まない - これは JS 変数の割り当てです)
    • __SKILL_NAME_PLACEHOLDER__-> スキルの名前
    • __SKILL_DESCRIPTION_PLACEHOLDER__-> スキルの現在の説明
  3. 一時ファイル (例:/tmp/eval_review_&lt;skill-name&gt;.html) に書き込み、それを開きます:open /tmp/eval_review_&lt;skill-name&gt;.html
  4. ユーザーはクエリを編集し、トリガーの切り替え、エントリの追加/削除を行ってから、[評価セットのエクスポート] をクリックします。
  5. ファイルは~/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 &lt;output_path&gt;を使用してスタンドアロン 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を実行します。
    • 定量的評価を実行する
  • あなたとユーザーが満足するまで繰り返します
  • 最終的なスキルをパッケージ化してユーザーに返します。

そのようなものがある場合は、忘れないように TodoList にステップを追加してください。 Cowork を使用している場合は、それが確実に行われるように、TodoList に「evals JSON を作成してeval-viewer/generate_review.pyを実行して人間がテスト ケースをレビューできるようにする」と具体的に入れてください。

頑張ってください!

リソースファイル

ライセンス.txt

LICENSE.txtをダウンロード

バイナリリソース

エージェント/アナライザー.md

エージェント/analyzer.md をダウンロード

バイナリリソース

エージェント/comparator.md

エージェント/comparator.md をダウンロード

バイナリリソース

エージェント/グレーダー.md

エージェント/grader.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

リファレンス/schemas.md をダウンロード

バイナリリソース

スクリプト/init.py

スクリプトをダウンロード/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

スクリプトをダウンロード/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_eval.py

バイナリリソース

スクリプト/run_loop.py

スクリプトをダウンロード/run_loop.py

バイナリリソース

スクリプト/utils.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

GitHub で見る

GitHub で見る

Current official reference · English8a1541c4a3ff

The original English source comes from the pinned version above. It is shown as inert documentation. Related scripts and resources remain in the upstream repository; this text is not a complete installation package.

Skill Creator

A skill for creating new skills and iteratively improving them.

At a high level, the process of creating a skill goes like this:

  • Decide what you want the skill to do and roughly how it should do it
  • Write a draft of the skill
  • Create a few test prompts and run claude-with-access-to-the-skill on them
  • Help the user evaluate the results both qualitatively and quantitatively
    • While the runs happen in the background, draft some quantitative evals if there aren't any (if there are some, you can either use as is or modify if you feel something needs to change about them). Then explain them to the user (or if they already existed, explain the ones that already exist)
    • Use the eval-viewer/generate_review.py script to show the user the results for them to look at, and also let them look at the quantitative metrics
  • Rewrite the skill based on feedback from the user's evaluation of the results (and also if there are any glaring flaws that become apparent from the quantitative benchmarks)
  • Repeat until you're satisfied
  • Expand the test set and try again at larger scale

Your job when using this skill is to figure out where the user is in this process and then jump in and help them progress through these stages. So for instance, maybe they're like "I want to make a skill for X". You can help narrow down what they mean, write a draft, write the test cases, figure out how they want to evaluate, run all the prompts, and repeat.

On the other hand, maybe they already have a draft of the skill. In this case you can go straight to the eval/iterate part of the loop.

Of course, you should always be flexible and if the user is like "I don't need to run a bunch of evaluations, just vibe with me", you can do that instead.

Then after the skill is done (but again, the order is flexible), you can also run the skill description improver, which we have a whole separate script for, to optimize the triggering of the skill.

Cool? Cool.

Communicating with the user

The skill creator is liable to be used by people across a wide range of familiarity with coding jargon. If you haven't heard (and how could you, it's only very recently that it started), there's a trend now where the power of Claude is inspiring plumbers to open up their terminals, parents and grandparents to google "how to install npm". On the other hand, the bulk of users are probably fairly computer-literate.

So please pay attention to context cues to understand how to phrase your communication! In the default case, just to give you some idea:

  • "evaluation" and "benchmark" are borderline, but OK
  • for "JSON" and "assertion" you want to see serious cues from the user that they know what those things are before using them without explaining them

It's OK to briefly explain terms if you're in doubt, and feel free to clarify terms with a short definition if you're unsure if the user will get it.


Creating a skill

Capture Intent

Start by understanding the user's intent. The current conversation might already contain a workflow the user wants to capture (e.g., they say "turn this into a skill"). If so, extract answers from the conversation history first — the tools used, the sequence of steps, corrections the user made, input/output formats observed. The user may need to fill the gaps, and should confirm before proceeding to the next step.

  1. What should this skill enable Claude to do?
  2. When should this skill trigger? (what user phrases/contexts)
  3. What's the expected output format?
  4. Should we set up test cases to verify the skill works? Skills with objectively verifiable outputs (file transforms, data extraction, code generation, fixed workflow steps) benefit from test cases. Skills with subjective outputs (writing style, art) often don't need them. Suggest the appropriate default based on the skill type, but let the user decide.

Interview and Research

Proactively ask questions about edge cases, input/output formats, example files, success criteria, and dependencies. Wait to write test prompts until you've got this part ironed out.

Check available MCPs - if useful for research (searching docs, finding similar skills, looking up best practices), research in parallel via subagents if available, otherwise inline. Come prepared with context to reduce burden on the user.

Write the SKILL.md

Based on the user interview, fill in these components:

  • name: Skill identifier
  • description: When to trigger, what it does. This is the primary triggering mechanism - include both what the skill does AND specific contexts for when to use it. All "when to use" info goes here, not in the body. Note: currently Claude has a tendency to "undertrigger" skills -- to not use them when they'd be useful. To combat this, please make the skill descriptions a little bit "pushy". So for instance, instead of "How to build a simple fast dashboard to display internal Anthropic data.", you might write "How to build a simple fast dashboard to display internal Anthropic data. Make sure to use this skill whenever the user mentions dashboards, data visualization, internal metrics, or wants to display any kind of company data, even if they don't explicitly ask for a 'dashboard.'"
  • compatibility: Required tools, dependencies (optional, rarely needed)
  • the rest of the skill :)

Skill Writing Guide

Anatomy of a Skill

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)

Progressive Disclosure

Skills use a three-level loading system:

  1. Metadata (name + description) - Always in context (~100 words)
  2. SKILL.md body - In context whenever skill triggers (<500 lines ideal)
  3. Bundled resources - As needed (unlimited, scripts can execute without loading)

These word counts are approximate and you can feel free to go longer if needed.

Key patterns:

  • Keep SKILL.md under 500 lines; if you're approaching this limit, add an additional layer of hierarchy along with clear pointers about where the model using the skill should go next to follow up.
  • Reference files clearly from SKILL.md with guidance on when to read them
  • For large reference files (>300 lines), include a table of contents

Domain organization: When a skill supports multiple domains/frameworks, organize by variant:

cloud-deploy/
├── SKILL.md (workflow + selection)
└── references/
    ├── aws.md
    ├── gcp.md
    └── azure.md

Claude reads only the relevant reference file.

Principle of Lack of Surprise

This goes without saying, but skills must not contain malware, exploit code, or any content that could compromise system security. A skill's contents should not surprise the user in their intent if described. Don't go along with requests to create misleading skills or skills designed to facilitate unauthorized access, data exfiltration, or other malicious activities. Things like a "roleplay as an XYZ" are OK though.

Writing Patterns

Prefer using the imperative form in instructions.

Defining output formats - You can do it like this:

## Report structure
ALWAYS use this exact template:
# [Title]
## Executive summary
## Key findings
## Recommendations

Examples pattern - It's useful to include examples. You can format them like this (but if "Input" and "Output" are in the examples you might want to deviate a little):

## Commit message format
**Example 1:**
Input: Added user authentication with JWT tokens
Output: feat(auth): implement JWT-based authentication

Writing Style

Try to explain to the model why things are important in lieu of heavy-handed musty MUSTs. Use theory of mind and try to make the skill general and not super-narrow to specific examples. Start by writing a draft and then look at it with fresh eyes and improve it.

Test Cases

After writing the skill draft, come up with 2-3 realistic test prompts — the kind of thing a real user would actually say. Share them with the user: [you don't have to use this exact language] "Here are a few test cases I'd like to try. Do these look right, or do you want to add more?" Then run them.

Save test cases to evals/evals.json. Don't write assertions yet — just the prompts. You'll draft assertions in the next step while the runs are in progress.

{
  "skill_name": "example-skill",
  "evals": [
    {
      "id": 1,
      "prompt": "User's task prompt",
      "expected_output": "Description of expected result",
      "files": []
    }
  ]
}

See references/schemas.md for the full schema (including the assertions field, which you'll add later).

Running and evaluating test cases

This section is one continuous sequence — don't stop partway through. Do NOT use /skill-test or any other testing skill.

Put results in <skill-name>-workspace/ as a sibling to the skill directory. Within the workspace, organize results by iteration (iteration-1/, iteration-2/, etc.) and within that, each test case gets a directory (eval-0/, eval-1/, etc.). Don't create all of this upfront — just create directories as you go.

Step 1: Spawn all runs (with-skill AND baseline) in the same turn

For each test case, spawn two subagents in the same turn — one with the skill, one without. This is important: don't spawn the with-skill runs first and then come back for baselines later. Launch everything at once so it all finishes around the same time.

With-skill run:

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">

Baseline run (same prompt, but the baseline depends on context):

  • Creating a new skill: no skill at all. Same prompt, no skill path, save to without_skill/outputs/.
  • Improving an existing skill: the old version. Before editing, snapshot the skill (cp -r <skill-path> <workspace>/skill-snapshot/), then point the baseline subagent at the snapshot. Save to old_skill/outputs/.

Write an eval_metadata.json for each test case (assertions can be empty for now). Give each eval a descriptive name based on what it's testing — not just "eval-0". Use this name for the directory too. If this iteration uses new or modified eval prompts, create these files for each new eval directory — don't assume they carry over from previous iterations.

{
  "eval_id": 0,
  "eval_name": "descriptive-name-here",
  "prompt": "The user's task prompt",
  "assertions": []
}

Step 2: While runs are in progress, draft assertions

Don't just wait for the runs to finish — you can use this time productively. Draft quantitative assertions for each test case and explain them to the user. If assertions already exist in evals/evals.json, review them and explain what they check.

Good assertions are objectively verifiable and have descriptive names — they should read clearly in the benchmark viewer so someone glancing at the results immediately understands what each one checks. Subjective skills (writing style, design quality) are better evaluated qualitatively — don't force assertions onto things that need human judgment.

Update the eval_metadata.json files and evals/evals.json with the assertions once drafted. Also explain to the user what they'll see in the viewer — both the qualitative outputs and the quantitative benchmark.

Step 3: As runs complete, capture timing data

When each subagent task completes, you receive a notification containing total_tokens and duration_ms. Save this data immediately to timing.json in the run directory:

{
  "total_tokens": 84852,
  "duration_ms": 23332,
  "total_duration_seconds": 23.3
}

This is the only opportunity to capture this data — it comes through the task notification and isn't persisted elsewhere. Process each notification as it arrives rather than trying to batch them.

Step 4: Grade, aggregate, and launch the viewer

Once all runs are done:

  1. Grade each run — spawn a grader subagent (or grade inline) that reads agents/grader.md and evaluates each assertion against the outputs. Save results to grading.json in each run directory. The grading.json expectations array must use the fields text, passed, and evidence (not name/met/details or other variants) — the viewer depends on these exact field names. For assertions that can be checked programmatically, write and run a script rather than eyeballing it — scripts are faster, more reliable, and can be reused across iterations.

  2. Aggregate into benchmark — run the aggregation script from the skill-creator directory:

    python -m scripts.aggregate_benchmark <workspace>/iteration-N --skill-name <name>
    

    This produces benchmark.json and benchmark.md with pass_rate, time, and tokens for each configuration, with mean ± stddev and the delta. If generating benchmark.json manually, see references/schemas.md for the exact schema the viewer expects. Put each with_skill version before its baseline counterpart.

  3. Do an analyst pass — read the benchmark data and surface patterns the aggregate stats might hide. See agents/analyzer.md (the "Analyzing Benchmark Results" section) for what to look for — things like assertions that always pass regardless of skill (non-discriminating), high-variance evals (possibly flaky), and time/token tradeoffs.

  4. Launch the viewer with both qualitative outputs and quantitative data:

    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=$!
    

    For iteration 2+, also pass --previous-workspace <workspace>/iteration-<N-1>.

    Cowork / headless environments: If webbrowser.open() is not available or the environment has no display, use --static <output_path> to write a standalone HTML file instead of starting a server. Feedback will be downloaded as a feedback.json file when the user clicks "Submit All Reviews". After download, copy feedback.json into the workspace directory for the next iteration to pick up.

Note: please use generate_review.py to create the viewer; there's no need to write custom HTML.

  1. Tell the user something like: "I've opened the results in your browser. There are two tabs — 'Outputs' lets you click through each test case and leave feedback, 'Benchmark' shows the quantitative comparison. When you're done, come back here and let me know."

What the user sees in the viewer

The "Outputs" tab shows one test case at a time:

  • Prompt: the task that was given
  • Output: the files the skill produced, rendered inline where possible
  • Previous Output (iteration 2+): collapsed section showing last iteration's output
  • Formal Grades (if grading was run): collapsed section showing assertion pass/fail
  • Feedback: a textbox that auto-saves as they type
  • Previous Feedback (iteration 2+): their comments from last time, shown below the textbox

The "Benchmark" tab shows the stats summary: pass rates, timing, and token usage for each configuration, with per-eval breakdowns and analyst observations.

Navigation is via prev/next buttons or arrow keys. When done, they click "Submit All Reviews" which saves all feedback to feedback.json.

Step 5: Read the feedback

When the user tells you they're done, read 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"
}

Empty feedback means the user thought it was fine. Focus your improvements on the test cases where the user had specific complaints.

Kill the viewer server when you're done with it:

kill $VIEWER_PID 2>/dev/null

Improving the skill

This is the heart of the loop. You've run the test cases, the user has reviewed the results, and now you need to make the skill better based on their feedback.

How to think about improvements

  1. Generalize from the feedback. The big picture thing that's happening here is that we're trying to create skills that can be used a million times (maybe literally, maybe even more who knows) across many different prompts. Here you and the user are iterating on only a few examples over and over again because it helps move faster. The user knows these examples in and out and it's quick for them to assess new outputs. But if the skill you and the user are codeveloping works only for those examples, it's useless. Rather than put in fiddly overfitty changes, or oppressively constrictive MUSTs, if there's some stubborn issue, you might try branching out and using different metaphors, or recommending different patterns of working. It's relatively cheap to try and maybe you'll land on something great.

  2. Keep the prompt lean. Remove things that aren't pulling their weight. Make sure to read the transcripts, not just the final outputs — if it looks like the skill is making the model waste a bunch of time doing things that are unproductive, you can try getting rid of the parts of the skill that are making it do that and seeing what happens.

  3. Explain the why. Try hard to explain the why behind everything you're asking the model to do. Today's LLMs are smart. They have good theory of mind and when given a good harness can go beyond rote instructions and really make things happen. Even if the feedback from the user is terse or frustrated, try to actually understand the task and why the user is writing what they wrote, and what they actually wrote, and then transmit this understanding into the instructions. If you find yourself writing ALWAYS or NEVER in all caps, or using super rigid structures, that's a yellow flag — if possible, reframe and explain the reasoning so that the model understands why the thing you're asking for is important. That's a more humane, powerful, and effective approach.

  4. Look for repeated work across test cases. Read the transcripts from the test runs and notice if the subagents all independently wrote similar helper scripts or took the same multi-step approach to something. If all 3 test cases resulted in the subagent writing a create_docx.py or a build_chart.py, that's a strong signal the skill should bundle that script. Write it once, put it in scripts/, and tell the skill to use it. This saves every future invocation from reinventing the wheel.

This task is pretty important (we are trying to create billions a year in economic value here!) and your thinking time is not the blocker; take your time and really mull things over. I'd suggest writing a draft revision and then looking at it anew and making improvements. Really do your best to get into the head of the user and understand what they want and need.

The iteration loop

After improving the skill:

  1. Apply your improvements to the skill
  2. Rerun all test cases into a new iteration-<N+1>/ directory, including baseline runs. If you're creating a new skill, the baseline is always without_skill (no skill) — that stays the same across iterations. If you're improving an existing skill, use your judgment on what makes sense as the baseline: the original version the user came in with, or the previous iteration.
  3. Launch the reviewer with --previous-workspace pointing at the previous iteration
  4. Wait for the user to review and tell you they're done
  5. Read the new feedback, improve again, repeat

Keep going until:

  • The user says they're happy
  • The feedback is all empty (everything looks good)
  • You're not making meaningful progress

Advanced: Blind comparison

For situations where you want a more rigorous comparison between two versions of a skill (e.g., the user asks "is the new version actually better?"), there's a blind comparison system. Read agents/comparator.md and agents/analyzer.md for the details. The basic idea is: give two outputs to an independent agent without telling it which is which, and let it judge quality. Then analyze why the winner won.

This is optional, requires subagents, and most users won't need it. The human review loop is usually sufficient.


Description Optimization

The description field in SKILL.md frontmatter is the primary mechanism that determines whether Claude invokes a skill. After creating or improving a skill, offer to optimize the description for better triggering accuracy.

Step 1: Generate trigger eval queries

Create 20 eval queries — a mix of should-trigger and should-not-trigger. Save as JSON:

[
  {"query": "the user prompt", "should_trigger": true},
  {"query": "another prompt", "should_trigger": false}
]

The queries must be realistic and something a Claude Code or Claude.ai user would actually type. Not abstract requests, but requests that are concrete and specific and have a good amount of detail. For instance, file paths, personal context about the user's job or situation, column names and values, company names, URLs. A little bit of backstory. Some might be in lowercase or contain abbreviations or typos or casual speech. Use a mix of different lengths, and focus on edge cases rather than making them clear-cut (the user will get a chance to sign off on them).

Bad: "Format this data", "Extract text from PDF", "Create a chart"

Good: "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"

For the should-trigger queries (8-10), think about coverage. You want different phrasings of the same intent — some formal, some casual. Include cases where the user doesn't explicitly name the skill or file type but clearly needs it. Throw in some uncommon use cases and cases where this skill competes with another but should win.

For the should-not-trigger queries (8-10), the most valuable ones are the near-misses — queries that share keywords or concepts with the skill but actually need something different. Think adjacent domains, ambiguous phrasing where a naive keyword match would trigger but shouldn't, and cases where the query touches on something the skill does but in a context where another tool is more appropriate.

The key thing to avoid: don't make should-not-trigger queries obviously irrelevant. "Write a fibonacci function" as a negative test for a PDF skill is too easy — it doesn't test anything. The negative cases should be genuinely tricky.

Step 2: Review with user

Present the eval set to the user for review using the HTML template:

  1. Read the template from assets/eval_review.html
  2. Replace the placeholders:
    • __EVAL_DATA_PLACEHOLDER__ → the JSON array of eval items (no quotes around it — it's a JS variable assignment)
    • __SKILL_NAME_PLACEHOLDER__ → the skill's name
    • __SKILL_DESCRIPTION_PLACEHOLDER__ → the skill's current description
  3. Write to a temp file (e.g., /tmp/eval_review_<skill-name>.html) and open it: open /tmp/eval_review_<skill-name>.html
  4. The user can edit queries, toggle should-trigger, add/remove entries, then click "Export Eval Set"
  5. The file downloads to ~/Downloads/eval_set.json — check the Downloads folder for the most recent version in case there are multiple (e.g., eval_set (1).json)

This step matters — bad eval queries lead to bad descriptions.

Step 3: Run the optimization loop

Tell the user: "This will take some time — I'll run the optimization loop in the background and check on it periodically."

Save the eval set to the workspace, then run in the background:

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

Use the model ID from your system prompt (the one powering the current session) so the triggering test matches what the user actually experiences.

While it runs, periodically tail the output to give the user updates on which iteration it's on and what the scores look like.

This handles the full optimization loop automatically. It splits the eval set into 60% train and 40% held-out test, evaluates the current description (running each query 3 times to get a reliable trigger rate), then calls Claude to propose improvements based on what failed. It re-evaluates each new description on both train and test, iterating up to 5 times. When it's done, it opens an HTML report in the browser showing the results per iteration and returns JSON with best_description — selected by test score rather than train score to avoid overfitting.

How skill triggering works

Understanding the triggering mechanism helps design better eval queries. Skills appear in Claude's available_skills list with their name + description, and Claude decides whether to consult a skill based on that description. The important thing to know is that Claude only consults skills for tasks it can't easily handle on its own — simple, one-step queries like "read this PDF" may not trigger a skill even if the description matches perfectly, because Claude can handle them directly with basic tools. Complex, multi-step, or specialized queries reliably trigger skills when the description matches.

This means your eval queries should be substantive enough that Claude would actually benefit from consulting a skill. Simple queries like "read file X" are poor test cases — they won't trigger skills regardless of description quality.

Step 4: Apply the result

Take best_description from the JSON output and update the skill's SKILL.md frontmatter. Show the user before/after and report the scores.


Package and Present (only if present_files tool is available)

Check whether you have access to the present_files tool. If you don't, skip this step. If you do, package the skill and present the .skill file to the user:

python -m scripts.package_skill <path/to/skill-folder>

After packaging, direct the user to the resulting .skill file path so they can install it.


Claude.ai-specific instructions

In Claude.ai, the core workflow is the same (draft → test → review → improve → repeat), but because Claude.ai doesn't have subagents, some mechanics change. Here's what to adapt:

Running test cases: No subagents means no parallel execution. For each test case, read the skill's SKILL.md, then follow its instructions to accomplish the test prompt yourself. Do them one at a time. This is less rigorous than independent subagents (you wrote the skill and you're also running it, so you have full context), but it's a useful sanity check — and the human review step compensates. Skip the baseline runs — just use the skill to complete the task as requested.

Reviewing results: If you can't open a browser (e.g., Claude.ai's VM has no display, or you're on a remote server), skip the browser reviewer entirely. Instead, present results directly in the conversation. For each test case, show the prompt and the output. If the output is a file the user needs to see (like a .docx or .xlsx), save it to the filesystem and tell them where it is so they can download and inspect it. Ask for feedback inline: "How does this look? Anything you'd change?"

Benchmarking: Skip the quantitative benchmarking — it relies on baseline comparisons which aren't meaningful without subagents. Focus on qualitative feedback from the user.

The iteration loop: Same as before — improve the skill, rerun the test cases, ask for feedback — just without the browser reviewer in the middle. You can still organize results into iteration directories on the filesystem if you have one.

Description optimization: This section requires the claude CLI tool (specifically claude -p) which is only available in Claude Code. Skip it if you're on Claude.ai.

Blind comparison: Requires subagents. Skip it.

Packaging: The package_skill.py script works anywhere with Python and a filesystem. On Claude.ai, you can run it and the user can download the resulting .skill file.

Updating an existing skill: The user might be asking you to update an existing skill, not create a new one. In this case:

  • Preserve the original name. Note the skill's directory name and name frontmatter field -- use them unchanged. E.g., if the installed skill is research-helper, output research-helper.skill (not research-helper-v2).
  • Copy to a writeable location before editing. The installed skill path may be read-only. Copy to /tmp/skill-name/, edit there, and package from the copy.
  • If packaging manually, stage in /tmp/ first, then copy to the output directory -- direct writes may fail due to permissions.

Cowork-Specific Instructions

If you're in Cowork, the main things to know are:

  • You have subagents, so the main workflow (spawn test cases in parallel, run baselines, grade, etc.) all works. (However, if you run into severe problems with timeouts, it's OK to run the test prompts in series rather than parallel.)
  • You don't have a browser or display, so when generating the eval viewer, use --static <output_path> to write a standalone HTML file instead of starting a server. Then proffer a link that the user can click to open the HTML in their browser.
  • For whatever reason, the Cowork setup seems to disincline Claude from generating the eval viewer after running the tests, so just to reiterate: whether you're in Cowork or in Claude Code, after running tests, you should always generate the eval viewer for the human to look at examples before revising the skill yourself and trying to make corrections, using generate_review.py (not writing your own boutique html code). Sorry in advance but I'm gonna go all caps here: GENERATE THE EVAL VIEWER BEFORE evaluating inputs yourself. You want to get them in front of the human ASAP!
  • Feedback works differently: since there's no running server, the viewer's "Submit All Reviews" button will download feedback.json as a file. You can then read it from there (you may have to request access first).
  • Packaging works — package_skill.py just needs Python and a filesystem.
  • Description optimization (run_loop.py / run_eval.py) should work in Cowork just fine since it uses claude -p via subprocess, not a browser, but please save it until you've fully finished making the skill and the user agrees it's in good shape.
  • Updating an existing skill: The user might be asking you to update an existing skill, not create a new one. Follow the update guidance in the claude.ai section above.

Reference files

The agents/ directory contains instructions for specialized subagents. Read them when you need to spawn the relevant subagent.

  • agents/grader.md — How to evaluate assertions against outputs
  • agents/comparator.md — How to do blind A/B comparison between two outputs
  • agents/analyzer.md — How to analyze why one version beat another

The references/ directory has additional documentation:

  • references/schemas.md — JSON structures for evals.json, grading.json, etc.

Repeating one more time the core loop here for emphasis:

  • Figure out what the skill is about
  • Draft or edit the skill
  • Run claude-with-access-to-the-skill on test prompts
  • With the user, evaluate the outputs:
    • Create benchmark.json and run eval-viewer/generate_review.py to help the user review them
    • Run quantitative evals
  • Repeat until you and the user are satisfied
  • Package the final skill and return it to the user.

Please add steps to your TodoList, if you have such a thing, to make sure you don't forget. If you're in Cowork, please specifically put "Create evals JSON and run eval-viewer/generate_review.py so human can review test cases" in your TodoList to make sure it happens.

Good luck!