プラグインの評価(evals)
claude plugin eval でプラグインのテストケースを書いて動かし、グレーダーで採点して、プラグインなしと比べ、CI の合否に使う方法を、ケースの形式の全表とともにまとめます。
claude plugin eval は、プラグインをテストケースの組(スイート)に対して動かして、結果を採点するシェルコマンドです。各ケースは、現実的なプロンプトと1つ以上のグレーダーでできています。グレーダーは、Claude が出したものへの合否の確認で、返答への正規表現、特定のツールが呼ばれたか、別のモデルが返答を判定する採点基準などです。作り方はプラグインを作って配る、コマンドの引数の一覧はプラグインのリファレンスにあります。
このページで分かること#
- eval でできること(プラグインが狙いの結果を出させる確かさの測定、変更やモデル更新での劣化の検出、プラグインなしとの差)
- 最初のスイートを作って動かし、結果を読む手順
- ケース・グレーダー・モック・フィクスチャの書き方と、全フィールドの表
- コマンドのオプション、CI での使い方、終了コード
- 結果(HTML レポートと JSON)の読み方、実行が触れられる範囲、トラブル対処
注意
eval の各実行と、判定モデルを使うグレーダーは、どれも自分のアカウントでの本物のモデル呼び出しで、プランの使用量か API の請求に数えられます。先に「必要なもの」を確かめます。
スイートは claude plugin eval init に書かせることもできます。プラグインについて尋ね、ケースとグレーダーを提案し、試し、ファイルを書きます。開いているセッションから Claude に頼んで同じことをさせることもできます。1つのスキルをその場で磨く用途には、スキルの文書にある skill-creator プラグインが、evals/evals.json という別の形式で似た比較をします。2つのツールは、互いのケースのファイルを読みません(スキル)。ファイルの構文やスキーマのエラーを確かめたいだけなら、claude plugin validate を使います。
必要なもの#
- Claude Code v2.1.269 以降(
claude --versionで確認、claude updateで更新) - git が入っているなら Git 2.31 以降(
git --versionで確認)。古い git では、claude plugin evalはケースを動かす前に止まります。git が無ければ普通に動きます plugin.jsonか.claude-plugin/plugin.jsonのマニフェストを持つプラグインのディレクトリ、またはスキルのディレクトリのプラグイン- 普段のセッションと同じ認証とモデルのプロバイダ。eval の実行・判定のグレーダー・
claude plugin eval initは、自分の資格情報でモデルを呼ぶので、プランの使用量の上限か API の請求に数えられます。コマンドが出すコストは、それらの呼び出しの定価ベースの見積もりです(コストを抑える)。Amazon Bedrock・Google Cloud の Agent Platform・Microsoft Foundry で Claude Code を動かしているなら、普段のセッションと同じプロバイダーの変数を書き出したシェルからスイートを実行します。各実行は、そのシェルからそれを引き継ぐためです(prompt.mdのenvフィールドの説明のとおり)。
実行の仕組み#
スイートは、プラグイン内の evals/ というディレクトリにあります。各ケースは、プロンプトと1つ以上のグレーダーを持つ、自分のサブディレクトリです。プロンプトは、プラグインを使う人が打ちそうなもの(スキルの1つが扱うべき依頼など)です。
- 実行:ケースの1回の実行ごとに、Claude Code が、プラグインだけを読み込んだ、新しい隔離された非対話のセッションを始め、プロンプトを送り、Claude が終わるか、ケースのターンか時間の上限に達するまで作業させる。各グレーダーが、最終的な返答・トランスクリプト・Claude が作ったファイルを確かめて、合否を出す
- 採点:非決定的なエージェントの1回の実行では分かることが少ないので、各ケースは既定で3回動く。1回の実行の点数は、合格したグレーダーの割合(重みを付けていれば重み付き)で、ケースの点数は実行の平均。ケースが合格するのは、点数が
--threshold(既定は1.0)を満たすとき - モデル呼び出しの量:スイートは、おおよそ、ケース数 × 実行回数のエージェント実行をプラグインありで、同じ数をプラグインなしの基準で行い、
llmかbaselineのグレーダー1つにつき、1回の実行ごとに短い判定の呼び出しを3回行う - プラグインなしの基準:高い点数だけでは、プラグインが役立ったことは分かりません(プラグインなしでも Claude が同じようにできたかもしれないため)。そこで、ケースの実行を、プラグインを読み込まずに繰り返し、
WITHとW/OUTの2つの点数を出す。その差のΔが、プラグインの寄与。プラグインありでもなしでも 1.0 のケースは、プラグインが合格させたのではない。この2組の実行を、with アームと without アームと呼ぶ
最初のスイートを作る#
自分のプラグインに1つのケースを書いて、動かし、結果を読みます。プラグインのルート(plugin.json か .claude-plugin/plugin.json があるディレクトリ)で端末を開き、試したいスキルが1つと、それを引き起こすはずの、ユーザーが打ちそうな依頼を用意します。
-
ケースを作る:プラグインのルートで次を実行する。Claude Code がこのディレクトリをまだ信頼していなければ、先に
Trust this plugin directory?と聞かれるのでyと答える。そのあと対話の Claude Code のセッションが開く。Claude はプラグインを読み、良い結果とは何かを尋ね、プラグインが働くべきプロンプトと働くべきでないプロンプトを提案し、それぞれのグレーダーを設計し、試しに1回動かして確かめ、プロンプトごとに1つのケースのディレクトリをevals/の下に(プロンプトにちなんだ名前で)書く。Claude がスイートの準備ができたと言ったら、/exitか Ctrl+D でセッションを終えてシェルに戻る。プラグインのルートで開いているセッションがすでにあれば、そこで Claude にclaude plugin eval initを動かすよう頼んでもよく、同じ質問がその会話で行われるbashclaude plugin eval init -
スイートを動かす:プラグインのルートで、
evals/のすべてのケースを動かす。ステップ1でこのディレクトリを信頼済みなので、すぐに始まる(ケースを手で書いたなら、最初にTrust this plugin directory? [y/N]と聞かれる)。各ケースはプラグインありで3回、なしで3回なので、1ケースで6回の実行。1回終わるごとに、その実行の点数と各グレーダーの判定の進捗の行が出るbashclaude plugin eval . -
要約を読む:終わると、要約の表と、レポートの出力先が出る。
WITHはプラグインありのケースの点数、W/OUTはなしの点数で、Δが正ならプラグインが点数を上げた。COSTはモデル呼び出しの定価ベースの見積もり、NOTESは、with アームで最も重みの大きい失敗したグレーダーの説明か、実行のエラーtextCASE WITH W/OUT Δ RUNS COST NOTES first-case 1.00 0.33 +0.67 6 $0.41 1 case(s) · mean Δ +0.67 · 74s · $0.41 Report: /Users/you/my-plugin/evals/results/2026-09-10T17-02-11-482Z/report.html Published: https://claude.ai/... · keep local next time with --no-publish -
レポートを開いて直す:
Published:の URL(無ければReport:のパス)を開くと、各実行の各グレーダーの判定と説明が見え、llmのグレーダーでは、判定の票と判定した抜粋も見える。Published:の行が出るのは、アカウントがレポートを公開できるときだけ。最初によくある発見は、Δがゼロ近くで、ケースのtool_used: Skillのグレーダーが失敗していること。Claude が自然な言い回しでスキルを選んでいない、という意味なので、スキルのdescriptionを直して、claude plugin eval .をもう一度動かして比べる
1つのケースを安く繰り返すには、1つのアームを1回だけ動かします。1回は結果がぶれるので、変更を信じる前に、既定の3回で確かめます。1つのアームでは、表に WITH・W/OUT・Δ の代わりに SCORE と PASS% の列が出ます。<case-name> は evals/ の下のディレクトリ名に置き換えます。
claude plugin eval . --case <case-name> --runs 1 --ablation none
ケースを書く#
claude plugin eval init が書くケースは、開いて変えて足せる、ただのファイルです。ケースは、プラグインの eval ディレクトリの下の、prompt.md・case.yaml・その両方を含むディレクトリです。各ケースに少なくとも1つのグレーダーを、graders/<name>.md のファイルか case.yaml の graders: の項目として与えます(無いと、ケースは読み込みに失敗します)。ケースをまとめるには、ケースでないディレクトリの下に入れ子にします。ケースのディレクトリの中にあるもの(graders/ やフィクスチャのファイル)は、そのケースのものです。新しいスイートでは、claude plugin eval init が書く次の配置を使います。
my-plugin/
├── .claude-plugin/plugin.json
├── skills/...
└── evals/
├── first-case/
│ ├── prompt.md # frontmatter: case fields; body: the prompt
│ ├── graders/
│ │ ├── criteria.md # frontmatter: type + options; body: rubric or pattern
│ │ └── skill-fired.md
│ └── case.yaml # optional: only for context.* fields
├── ignores-unrelated-request/
│ └── ...
└── results/ # written by each run; add to .gitignore
ケースを手で書く#
Claude に claude plugin eval init でケースを書かせるのが推奨の道です。自分で書くなら、空のテンプレートから始めます。次のコマンドは、first-case という名前のケースを、仮の prompt.md と仮のグレーダー1つで書き、何も動かしません。
claude plugin eval init --bare first-case
evals/first-case/
├── prompt.md # the prompt sent to Claude, plus run limits
└── graders/
└── criteria.md # one grader: how to score the result
prompt.md には、各実行で Claude が受け取るメッセージを書き、フロントマターに、実行の上限とケースが使えるツールを設定します。仮の本文を、スキルが扱うべき依頼に置き換えます。スキルの名前を出さず、ユーザーが打つ言い方で書きます。次はコミットメッセージの下書きをするスキルの例です。
---
max_turns: 10
allowed_tools: [Read, Glob, Grep, Skill]
---
Write me a commit message for this change: I renamed getUser to fetchUser and updated the three call sites.
各実行は空の作業ディレクトリで始まるので、作業に要るものはプロンプトに入れるか、先に作業場所を整えます。graders/ の各ファイルは、実行のあとに適用する1つの確認です。evals/first-case/graders/criteria.md の仮の内容を、判定モデル向けの採点基準(具体的な PASS と FAIL の条件)に置き換えます。
---
type: llm
---
PASS if <what a correct response contains>.
FAIL if <what a wrong or missing response looks like>.
次に、答えを出したのが自分のスキルかを確かめる2つ目のグレーダーを足します。evals/first-case/graders/skill-fired.md を作り、your-skill-name を skills/ の下のスキルのディレクトリ名(Claude がスキルを呼ぶときの名前)に置き換えます。
---
type: tool_used
tool: Skill
input_match: '"skill"\s*:\s*"(?:[\w-]+:)?your-skill-name"'
---
これは、plugin-name:skill-name の名前空間つきの形も含めて、実行中に Claude がそのスキルを少なくとも1回呼んだときに通ります。2つのファイルを保存したら、プラグインのルートから claude plugin eval . で動かします。
prompt.md の実行の上限とツール#
ケースの max_turns・timeout_seconds・model・tags と、使ってよい allowed_tools は、prompt.md のフロントマターに設定します(全フィールドと既定値は下の表)。Claude は本文を書いたままに受け取ります。本文の @path の言及はファイルの添付に展開されないので、Claude がファイルを読む必要があるなら、allowed_tools でそのためのツールを許します。
グレーダーを選んで重みを付ける#
グレーダーのフロントマターは type を設定し、任意で、実行の点数への寄与を大きくする weight と、基準との採点を制御する arm を設定します。6つの種類のうち、regex・tool_used・tool_order・file_exists はトランスクリプトとファイルから計算され無料で、llm と baseline は判定モデルを呼ぶので実行のコストが増えます。カスタムコードのグレーダーはありません。llm と baseline のグレーダーの判定モデルは、既定では Claude Code がバックグラウンドタスクに使うモデルです。--judge-model sonnet か完全なモデル ID で、自分で判定モデルを選べます。
llm グレーダーはモデルに判定を求めるので、答えが実行ごとに変わることがあり、読む文章が長いほど変わりやすくなります。スイートの点数を信頼できる程度に安定させる心がけは、次のとおりです。
ヒント
- 生成したファイルのような長い出力は、ファイルの中身への
regexグレーダーで採点します。毎回同じ方法でファイル全体を確かめます。llmグレーダーは短い出力のために取っておき、採点基準は具体的な PASS と FAIL の条件で書きます - 各ケースに、結果(最終メッセージや作られたファイル)への1つと、それを作るために Claude がとった手順(
tool_usedやtool_order)への1つのグレーダーを置きます。答えが正しかったか、プラグインが作ったか、の両方が分かります - ケースの
tool_used: Skillのグレーダーが通るのにΔが負なら、プラグインより先に判定を疑います。小さな判定モデルは、採点基準の書き方と違う形式の正しい答えを誤りと判定することがあります。--judge-model sonnetでやり直し、形式で判定が決まらないよう採点基準を締めます - 実行の中でビルドやテストが通ったかを確かめるには、プロンプトで Claude にそれを動かして結果をファイルへ書くよう頼み、そのファイルを採点し、コマンドを名指しする
input_matchのtool_usedのグレーダーで、コマンドが動いたことも確かめます
プラグインなしの基準で採点する#
プラグインを試すとき、ケースは普通2つのアームで動きます。with アームはプラグインを読み込んだ実行で、without アームはプラグインなしの同じ数の実行です。要約とレポートは、2つの点数と、with から without を引いた Δ を出します。次の場合、ケースは with アームだけを動かすので、W/OUT の点数も Δ も付きません。
--ablation noneを渡す:すべてのケースが1つのアームだけを動かし、比較が要らないとき(グレーダーを直しているときなど)にコストが半分になる- ケースがトランスクリプトを再開し、対象がパスである:
.のようなパスの対象(入れたプラグインの名前でなく)では、context.history_fileのケースは、記録された会話がすでにプラグインを反映している前提で、既定で1つのアームで動く。実行は、これらのケースを名指しするsingle-arm (no Δ)の通知を標準エラーへ出す。再開したターンをプラグインありとなしで比べるには、--ablation with-withoutを渡す - ケースのためのプラグインが見つからない:対象がパスのとき、Claude Code がプラグインを見つけられなかったケースも、既定で1つのアームで動く(直し方は下のトラブル対処)
2つのアームの実行では、一部のグレーダーは scored: false で報告されます。「スキルが呼ばれた」のような確認は、プラグインなしでは通りえないので、数えると without アームがゼロに寄り、Δ が膨らみます。2つのアームを比べられるよう、Claude Code はそのようなグレーダーを両方のアームの点数から外し、with アームでは合否の目印としてだけ報告します。対象は次のとおりです。
toolがSkillの、すべてのtool_usedグレーダー- ケースの各モック化したサーバーが、自分のプラグインが宣言するものであるとき、
target: mock_callsのすべてのregexグレーダーと、focus: mock_callsのすべてのllmグレーダー arm: with-onlyを付けたグレーダー
この除外を変える設定は3つあります。
- すべてのグレーダーが外される:ケースのグレーダーがすべて外される集合に入るときは、採点するものが残らないので、通常どおり採点される
arm: both:グレーダーにarm: bothを付けると、どちらのアームでも採点される。min: 0とmax: 0の「スキルを呼んではいけない」確認に使う--ablation none:--ablation noneでは何も外されないので、同じスイートでも、2つのモードで絶対の点数が違うことがある
別の eval ディレクトリを使う#
evals/ が他のツールにすでに使われているなら、別のディレクトリにスイートを置けます。そのディレクトリを、全実行と全協力者が使うようにするには、プラグインの plugin.json に "experimental": { "evals": "quality/evals" } と書きます。1回の実行だけなら、claude plugin eval と claude plugin eval init の両方に --eval-dir quality/evals を渡します。両方設定すると、フラグのディレクトリが使われます。qa や quality/evals のように、普通のディレクトリ名からなる相対パスを渡します。絶対パスや .. を含むパスは受け付けられず、フラグの値ならエラー、マニフェストの値が使えないときは Warning: の行が出て、evals/ が使われます。ケース・結果・init の出力は、すべてそのディレクトリへ移ります。
フィクスチャとモックを用意する#
ケースには、プロンプト以上のもの(作業場所のファイルや git リポジトリ、続きにする前の会話、プラグインがつなぐ MCP サーバーの答え)が要ることがあります。それぞれをケースの横に用意するので、実行を繰り返せます。
作業場所や会話を用意する#
各実行は空の作業場所で始まります。ケースがプロンプト以上を要するときは、prompt.md の隣の case.yaml に context ブロックを足します。
- フィクスチャのファイルか git リポジトリ:ケースのディレクトリに Bash のスクリプトを書き、
context.scaffold_scriptに名前を書く。スクリプトは、自分として、エージェントのサンドボックスの外で、--scaffoldを渡したときだけ動くので、このフラグは、自分か組織が書いたスイートにだけ渡す - 続きにする前の会話:トランスクリプトを
.jsonlファイルで保存し、context.history_fileに名前を書くと、ケースのプロンプトが次のユーザーのターンになる。対象がパスのとき、このようなケースは既定で基準のアームなしで動く - 実行中に Claude が読めるフィクスチャのディレクトリ:
context.add_dirsに並べる
case.yaml には、schema_version: "1.1" と name も必要です(全フィールドは下の表)。次の case.yaml は、スクリプトから作業場所を用意し、Claude が resources/ ディレクトリのフィクスチャを読めるようにします。
schema_version: "1.1"
name: changelog-from-diff
tags: [smoke]
context:
scaffold_script: fixture.sh
add_dirs: [resources]
用意のスクリプトは、空の作業場所で、小さな固定の環境で始まります。シェルの PATH、実行の一時ホームディレクトリを指す HOME、TMPDIR、TERM=dumb のようないくつかの定数です。シェルのほかのものも、ケースの EVAL_* 変数も届きません。スクリプトが 0 以外で終了するか120秒より長く動くと、その実行は scaffold failed のエラーで 0 点になります。スクリプトはファイルと git の状態のためだけに使います(スクリプトが書いたプロジェクトの設定は読み込まれません)。
MCP サーバーをモックする#
スキルが MCP ツールを呼ぶプラグインを、後ろの本物のサービスなしで評価できます。ツールごとに1つの Markdown ファイルを、スイート全体なら evals/mocks/<server>/<tool>.md、1つのケースだけならそのケース自身の mocks/ ディレクトリに置きます。<server> は、プラグインの MCP 設定でのサーバーの名前です(MCP サーバーをつなぐ)。
実行は、頼まない限り、プラグインの本物の MCP サーバーを起動しません。Claude Code は、各サーバー自身の名前で代わりのサーバーを登録します。モックのファイルを持つツールはそこから答え、--allow-tools の許可なしで許され、モックのファイルが無いツールは Claude に使えません。モックがまったく無いサーバーは、ケースの mocked: の進捗の行に plugin_<plugin>_<server>[not started: no mock] と出ます。ファイルの本文が、ツールが Claude に返すものです。次のモックは、tracker という名前のサーバーの create_issue ツールの代わりになり、Claude が送る入力を確かめ、題をそのまま返します。evals/mocks/tracker/create_issue.md として保存します。
---
expect:
title: string
priority: [low, medium, high]
---
Created issue #4821: {{input.title}}
モックのファイルの本文とフロントマターは、次を受け付けます。
- 置換:
{{input.<field>}}で呼び出しの入力のフィールドを、{{file:fixtures/{input.<field>}.json}}でモックの隣のフィクスチャファイルの中身を差し込む expect::入力を守る。呼び出しが違反すると、実行は 0 点で中断し、理由を記録するので、プラグインがサーバーに頼んだ内容を、ケースで検証できるerror: true:本文を、ツールのエラーとして返すtype: agent:本文の指示に従って、判定モデルがサーバーとして答える
呼び出し自体を採点するには、グレーダーを target: mock_calls に向けます。プラグインの本物の MCP サーバーに対して動かすには、次のフラグを渡します。どちらの場合も、そのプロセスは、実行のサンドボックスの外で、自分として動き、ツールには --allow-tools の許可が要ります。
--allow-real-servers:モックしていない各サーバーの本物のプロセスを起動し、モック化したツールはファイルから答え続ける--mocks off:mocks/を丸ごと無視し、プラグインが宣言するすべてのサーバーを起動する
type: agent のモックは、--judge-model への呼び出しで答えるので、出力は実行ごとに変わり、判定モデルを変えると変わります。実行がエラーや中断なしで終わると、Claude Code は、エージェントのモックが返した各答えを、結果のディレクトリの mock-recordings/ に保存します。そこの ADOPT.txt を開くと、各記録と、それを作ったモックの隣の、コピー先の .replay/<server>/ ディレクトリが分かります。記録をそこへコピーすると、あとの実行は同じ呼び出しに、モデル呼び出しなしでその記録から答えます。CI の実行を繰り返せるよう、mocks/.replay/ を mocks/ の残りと一緒にコミットします。
eval を動かす#
スイートがあれば、claude plugin eval が動かします。対象の引数でどのプラグインとケースを動かすかを選び、読み取り専用のセット以外のケースに要るツールは --allow-tools で許し、実行回数・モデル・コスト・出力は他のオプションで制御します。
何を評価するか#
たいていは、プラグインのルートで claude plugin eval . を動かし、立っているプラグインを読み込んで、スイートのすべてのケースを動かします。1つのケースのファイルや、開発中でなく入れたプラグインを評価するには、別の対象を渡します。
| 対象 | 動くもの |
|---|---|
. のようなプラグインのルートのディレクトリ |
その eval ディレクトリの下のすべてのケース。そのプラグインを読み込む |
1つの prompt.md か case.yaml ファイル |
そのケース。それを囲むプラグインを読み込む |
入れたプラグインの名前、name か name@marketplace |
入れたコピーの eval ディレクトリのケース。入れたコピーを読み込む。結果は、現在のディレクトリの ./evals/results/(--eval-dir なら ./<dir>/results/)に書かれる |
name@skills-dir |
スキルのディレクトリのプラグインについて同じ |
| 省略 | 現在のディレクトリをパスとして |
ケース名で絞るには --case <glob>、指定したタグのどれかを持つケースだけにするには --tag <tag> を足します。対象は、--tag・--allow-tools・--json の前に置きます。最初の2つはリストを、--json は任意のパスを取るので、後ろに続く対象を自分の値として読みます。
ツールを許す#
実行は、許可を求めて止まることがありません。許可を与えていない、Bash・Write・Edit・WebFetch・WebSearch のような許可が要る組み込みツールは、セッションから外され、Claude は呼べません。実行が許すのは、ケースが allowed_tools に並べた読み取り専用のツール(Read・Glob・Grep・NotebookRead・Skill・AskUserQuestion・Agent・TodoWrite、タスクのツールの TaskCreate・TaskGet・TaskList・TaskUpdate・TaskStop)と、--allow-tools で許したものだけです。この許可は、その実行のすべてのケースに適用されます。
claude plugin eval . --allow-tools Write Edit "Bash(npm test *)"
ケースが許可していないツールを求めたとき、進捗の出力は not granted として一覧にします。モックした MCP サーバーのツールには許可が要りません。本物のプラグインの MCP サーバーのツールには、サーバーの起動(--allow-real-servers か --mocks off)と、--allow-tools "mcp__plugin_my-plugin_github__*" のような名前での許可の両方が要ります(プラグインの MCP ツールの名前は mcp__plugin_<plugin>_<server>__<tool>)。
Bash をどんな形でも許すと、すべてのコマンドが Claude Code の OS レベルのサンドボックスの下で動きます。書き込みは実行の作業場所に限られ、ホームディレクトリと Claude Code の設定は読めず、ネットワークは --allow-tools "WebFetch(domain:example.com)" で許したドメインに限られます。サンドボックスのバックエンドが無いマシンで Bash か PowerShell を許すと、Claude Code は、制限なしで動かさず、各実行を拒否し、ケースは実行エラーを示して、たいてい 0 点になります。ネイティブの Windows にはバックエンドが無いので、シェルを許すスイートは WSL2 で動かし、Linux では先に bubblewrap と socat を入れます(サンドボックス)。
コマンドのオプション#
実行回数・モデル・採点・コスト・ツールの許可・モック・出力のオプションは次のとおりです。完全な一覧は claude plugin eval --help にあり、--case・--tag・--eval-dir・--no-scaffold・--report・--verbose も含みます。
| オプション | 既定 | 効果 |
|---|---|---|
--runs <n> |
各ケースの runs、無ければ3 |
アームごと・ケースごとの実行回数 |
-j・--concurrency <n> |
1 |
同時に動かすエージェントの実行数(1〜8)。アカウントのレート制限を共有するので、制限を超えるスループットではなく実時間を縮める。結果はケースの順序を保つ |
--model <model> |
各ケースの model、無ければ設定されていれば ANTHROPIC_MODEL、無ければ Claude Code の既定 |
試験するエージェントのモデル。モデルの更新をプラグインの劣化と取り違えないよう、CI では固定する |
--judge-model <model> |
バックグラウンドタスクのモデル | llm と baseline のグレーダーのモデル |
--ablation <mode> |
ケースごとに決まる | プラグインの寄与を測るため、プラグインなしでも各ケースを動かすか。none は1つのアーム、with-without はプラグインなしの基準を足す |
--threshold <0..1> |
1.0 |
with アームの点数がこれ以上なら、ケースが合格。これを下回るケースが1つでもあると、コマンドは 1 で終了する |
--max-cost-usd <usd> |
上限なし | 実行の定価ベースのコスト見積もりの上限(プランの使用量の上限ではない)。各実行の開始前に確かめる。使い切ると、何も新しく始まらない(すでに始まった実行は終わるので、支出はその分だけ超えうる)。未開始の実行が残ると、コマンドは途中までの結果で 2 で終了する |
--allow-tools <tools...> |
なし | 読み取り専用のセット以外のツールを許す |
--scaffold |
オフ | 各ケースの scaffold_script を動かす |
--trust-plugin |
オフ | コードとスイートを自分でも動かすプラグインについて、初回の信頼のプロンプトを飛ばす。ジョブがプロンプトに拒否されたり待たされたりしないよう、CI では渡す |
--mocks <mode> |
record |
record は、MCP ツールの呼び出しにモックから答え、プラグインの本物のサーバーは起動せず、エージェントのモックの答えを再生用に保存する。off はモックを無視して、プラグインの本物の MCP サーバーを起動する |
--allow-real-servers |
オフ | --mocks record で、モックのないサーバーについて、プラグインの本物の MCP サーバーも起動する |
--json [path] |
オフ | 結果のドキュメントを標準出力へ出すか、.json で終わるパスへ書く。実行は静かで、進捗の行も要約の表も出ない |
--output-dir <dir> |
<eval dir>/results/<timestamp>/ |
aggregate-result.json と report.html の出力先 |
--no-publish |
HTML のレポートを手元だけに置く | |
--publish-report |
Claude Code のセッションが始めた実行のように、既定では手元に残る場合でもレポートを公開する | |
--keep-temp |
オフ | Claude が作ったものをデバッグするため、各実行のサンドボックスのディレクトリを残して、パスを出す |
CI で動かす#
CI のジョブでは、結果を保存するため --json で動かし、終了コードでビルドを失敗させます。初回の信頼のプロンプトでジョブが待たないよう --trust-plugin を渡し、点数を時間をまたいで比べられるよう2つのモデルを固定し、レポートは手元だけに置き、上限としてコストの天井を設定します。
claude plugin eval . \
--trust-plugin \
--json results.json \
--threshold 0.8 \
--model claude-sonnet-5 \
--judge-model claude-haiku-4-5 \
--no-publish \
--max-cost-usd 20
| 終了コード | 意味 |
|---|---|
| 0 | すべてのケースが --threshold 以上の点数で、すべてのケースのファイルが読み込めた |
| 1 | しきい値を下回るケースがある、ケースのファイルの読み込みに失敗した、ケースが見つからない、実行を始められなかった、プラグインのディレクトリが信頼されておらず --trust-plugin も渡していない、またはオプションが不正 |
| 2 | 途中までの実行:--max-cost-usd の天井に達したか、最初の実行の前か最中に資格情報が拒否された。results.json は partial: true と理由つきで書かれる |
| 130 | 中断された。途中までの結果が書かれる |
| 143 | CI のタイムアウトなどで、終了させられた |
with から without を引いた差は報告されますが、終了コードを変えません。HTML のレポートの書き込みや公開の問題も変えません。ケースの点数が低い理由を見るには、--json なしで手元で動かして、実行ごとの進捗とグレーダーの行を出させます。CI のランナーには次も要ります。
- インストールと資格情報:Claude Code のインストールと、
ANTHROPIC_API_KEYやクラウドプロバイダーの変数のような環境の資格情報 - 信頼:
--trust-pluginなしで、チェックアウトのディレクトリを Claude Code がまだ信頼していないジョブには、初回の信頼のプロンプトが要り、尋ねられない実行は1で拒否される init:claude plugin eval initは質問のために端末が要る。CI ではclaude plugin eval init --bare <name>で空のテンプレートを得る
コストを予測できるようにするには、変更のたびの素早いスイートには判定を呼ばないグレーダーだけを置き、Δ が要らないところでは --ablation none を使い、partial: true のドキュメントと skippedPaidGraders を持つ実行は、グラフにする推移から外します。
結果を読む#
少なくとも1つのケースを動かすと、eval ディレクトリの中に results/<timestamp>/ ディレクトリが書かれ、aggregate-result.json と report.html が入ります。パスの対象ではプラグインの下、名前で指定したプラグインでは現在のディレクトリの下です。要約の表・JSON・レポートは、同じ結果のデータを描きます。
HTML レポート#
report.html は、外への要求をしない、1つの自己完結したファイルなので、CI のジョブに添付したり、ディスクから開いたりできます。上から読みます。
- 判定の行とタイル:スイート全体で、プラグインが役立ったかに答える。Suite score はケースごとの、プラグインありの点数の平均、Ablation Δ は基準の点数よりどれだけ上か下か、Cases はしきい値を満たしたケースの数、Perfect runs はすべてのグレーダーが通った、プラグインありの実行の割合
- 各ケースのカード:ケース自身の
Δとプラグインありの点数を、バーのしきい値に目盛りを付けて示す。Δが負のケースは左端が赤になり、スクロールしても劣化が目立つ - ケースの中:プラグインありの実行が先で、基準の実行が後。各実行が、グレーダーを合否のチップとともに並べる。失敗したグレーダーは、説明つきですでに展開されていて、
llmのグレーダーは判定の票と見せた証拠も出すので、点数が低い理由が分かる。tool_used: Skillのように点数に数えられないグレーダーには、plugin-fired indicatorのバッジが付く - Prompt と Graders:実行の下にあり、ケースのプロンプトと各グレーダーの採点基準かパターンが出るので、スイートなしでレポートを読む人にも、何を頼み、何が良いとされたかが分かる
claude.ai のサブスクリプションでサインインしていて、アカウントでアーティファクトが使えるなら、Claude Code は、レポートを非公開のアーティファクトとして公開し、Published: <url> と出します(アーティファクト)。手元だけにするには --no-publish を渡します。API キーの認証のように Published: の行が出ないときは、手元のファイルがレポートです。Claude Code のセッションが始めた実行(Claude にスイートを動かすよう頼んだときなど)も、手元に残り、Report: の行が kept local と言います。公開するには、そのコマンドに --publish-report を足します。
JSON の結果#
aggregate-result.json と --json の出力は、CI のスクリプトが解析できる、schemaVersion: 1 の版つきドキュメントです。フィールド名は camelCase で、新しいフィールドは既存のものを名前変更せずに足されるので、スクリプトは知らないフィールドを無視するように書きます。合否判定のスクリプトが普通読むフィールドは次のとおりです(ドキュメントは、スイートの設定、すべてのグレーダーの定義、説明と証拠つきの実行ごとのグレーダーの結果も持ちます)。
| フィールド | 意味 |
|---|---|
partial・partialReason |
スイートが終わらなかったとき、true と cost_ceiling・interrupted・auth_failed のどれか。推移のグラフから外す |
aggregates.overallScore |
スイート全体のケースの点数の平均 |
aggregates.casesPassed・aggregates.casesTotal |
--threshold 以上のケースの数と、合計 |
aggregates.meanDelta |
2つのアームのモードでの、ケースにわたる Δ の平均 |
cases[].name |
ケース名 |
cases[].aggregates.score |
ケースの with アームの実行の点数の平均 |
cases[].aggregates.delta |
with アームの点数から without アームの点数を引いたもの。ケースが1つのアームで動いたか、アームが比べられないときは省かれる |
cases[].arms.with[].error |
null、または実行が異常終了した理由(timed out after 300s など)。始まったが悪く終わった実行も、作ったものに対して採点されるので、null でないことは 0 点を意味しない |
cases[].arms.with[].aborted |
モックの expect: か abort_when が実行を止めたとき、server・tool・reason とともに出る。実行は 0 点になり、error は null のまま |
cases[].arms.with[].skippedPaidGraders |
コストの天井がその実行の判定のグレーダーを飛ばしたとき true。点数は比べられない |
costUsd・durationSeconds・claudeVersion |
判定の呼び出しを含む定価ベースのコスト見積もり、実時間の秒数、スイートを動かした Claude Code の版 |
実行が触れられる範囲#
claude plugin eval は、対象のプラグインのスキル・フック・エージェントを読み込み、その eval スイートを自分のマシンで自分として動かします。プラグインを指すことは claude --plugin-dir と同じ信頼の判断なので、信頼できるプラグインだけを評価します。ここで説明する隔離は、試験されるエージェントが届くものを制限するもので、プラグイン自身のコードへの境界ではありません。スイートが通っても、プラグインが安全かどうかは何も言えません。
プラグインのディレクトリを信頼する#
あるディレクトリに対して初めて claude plugin eval を動かすと、Claude Code は、そこから何かを読み込む前に Trust this plugin directory? と尋ねます(そこで対話の claude セッションの信頼のプロンプトをすでに承認していれば尋ねません)。git リポジトリの中では、yes と答えるとリポジトリ全体を信頼し、対話のセッションにも及びます。標準入力か標準出力が端末でないとき、または --json では、実行は尋ねられず 1 で拒否されます。自分のマシンで動かすプラグインにだけ、--trust-plugin で自分で信頼を宣言します。パスでなく名前で指定した対象(入れたプラグインかスキルのディレクトリのプラグイン)は、プロンプトを飛ばします。プラグインとスイートの一部は、その実行でフラグを渡したときだけ動きます。
- ケースの
scaffold_script:--scaffoldで - 読み取り専用のセット以外のツール:
--allow-toolsで - プラグインの本物の MCP サーバー:
--allow-real-serversか--mocks offで
ケースの allowed_tools と、スキル自身の allowed-tools のフロントマターは、これらのどれも広げられません。自分が書いていないフックをプラグインが含むとき、または本物の MCP サーバーを起動するときは、コンテナや CI のランナーのような隔離環境で動かしたのでない限り、その点数は参考として扱います(フックとサーバーはエージェントのサンドボックスの外で動き、採点に使うファイルを変えうるため)。
実行の隔離#
各実行は、一時のホームディレクトリ・作業ディレクトリ・Claude Code の設定を得て、試験されるエージェントはそこで、自分のプラグインだけを読み込んだ claude -p の子プロセスとして動きます。ケースを書くときは、次の結果を踏まえます。
- 個人のものもプロジェクトのものも読み込まれない:ユーザー設定・フック・
CLAUDE.md・MCP サーバー・他に入れたプラグイン・メモリ・スキルは無い。プロジェクトスコープの設定も、どこからも読まれない(作業場所の上でも中でも、用意のスクリプトが書いたものでも、.claude/・CLAUDE.md・.mcp.jsonは読み込まれず、add_dirsのディレクトリは読み取りのアクセスだけを与える)。シェルの環境の大半も渡らず、許可リストとEVAL_*変数だけが実行に届く。ケースが頼るスキル・エージェント・フック・MCP サーバーは、試験するプラグインに入れて配る(用意のスクリプトが与えられるのはファイルと git の状態だけ) - 管理ポリシーは実行を制限しうる:管理者がマシンに配った管理設定の制限は、実行の中でも適用されるので、管理されたマシンでの結果は、そのポリシーのぶん、管理されていないマシンと違うことがある
- Artifact ツールはオフ:アーティファクトを公開するスキルは、その手前までに作ったものでしか採点できない
- ケースの定義はエージェントから隠される:実行は eval ディレクトリを読めないので、Claude はケースのプロンプト・グレーダー・兄弟のケースを見られない
- シェルコマンド以外にはネットワークのサンドボックスが無い:許したシェルコマンドはサンドボックスのネットワークの規則の下で動く。
WebFetch(domain:…)の許可はそのドメインに直接届き、プラグイン自身のフックや、起動した本物の MCP サーバーは、どのホストにも届く
eval スイートのリファレンス#
スイートに入りうるものはすべて、プラグインの eval ディレクトリ(別のものを設定しない限り evals/)の下にあります。prompt.md か case.yaml を持つディレクトリがケースとして数えられ、グレーダーが少なくとも1つ無いケースは、graders を名指しする invalid case.yaml のエラーで読み込みに失敗します。claude plugin eval が eval ディレクトリで読み書きするすべてのファイルは次のとおりです。
evals/
├── <case>/ # one directory per case; nest under a non-case directory to group
│ ├── prompt.md # frontmatter: case and run fields; body: the prompt
│ ├── case.yaml # optional: context.* fields, or the whole case in one file
│ ├── graders/
│ │ └── <name>.md # one grader per file; frontmatter: type and options; body: rubric
│ ├── mocks/ # optional: mocks for this case only, same layout as below
│ └── <fixtures, scripts, transcripts referenced by case.yaml>
├── mocks/ # optional: suite-wide MCP mocks
│ ├── <server>/
│ │ ├── <tool>.md # one mocked tool; body: the tool result
│ │ ├── _server.md # optional: one agent that answers several tools
│ │ ├── _tools.json # optional: saved tools/list response for real descriptions and schemas
│ │ └── fixtures/ # files inserted with {{file:fixtures/...}}
│ └── .replay/<server>/ # adopted agent-mock recordings, answered without a model call
└── results/<timestamp>/ # written by each run; add results/ to .gitignore
├── aggregate-result.json
├── report.html
└── mock-recordings/ # agent-mock answers from clean runs, with ADOPT.txt
prompt.md のフロントマター#
prompt.md のフロントマターは、次のフィールドを受け付けます。未知のキーはエラーです。
| フィールド | 既定 | 目的 |
|---|---|---|
schema_version |
"1.1"(自動で設定される) |
ケースの形式の版。prompt.md で書いたケースには自動で付くので、ほとんど設定しない |
name |
ディレクトリ名 | ケース名。--case の glob が照合し、レポートがこれをキーにする |
description |
人のため。実行時には使われない | |
tags |
[] |
--tag の絞り込み用のラベル。タグのどれかが合えばケースが動く |
plugins |
最も近い、囲むプラグイン | 試験するプラグインのディレクトリ。ケースのディレクトリからの相対。自動検出がプラグインを見つけないときは plugins: ["../.."] を設定する |
runs |
3 |
アームごとの実行回数(1〜50)。--runs が上書きする |
expected_outcome |
人のため。実行時には使われない | |
model |
子セッションの既定 | 試験するエージェントのモデル。--model が上書きする |
max_turns |
10 |
ターンの上限(200まで)。到達すると実行のエラーとして記録され、たいてい点数が下がるので、多めに設定する |
timeout_seconds |
300 |
実行ごとの実時間の上限(3600まで) |
allowed_tools |
[] |
ケースが望むツール([Read, Glob, Grep, Skill] など)。読み取り専用のツールは、ここに並べると許される。それ以外は、上の「ツールを許す」 |
append_system_prompt |
子セッションのシステムプロンプトに足すテキスト | |
env |
{} |
子セッションの追加の環境変数。キーは EVAL_[A-Z0-9_]* に合う必要があり、他のキーは実行を失敗させる。実行がシェルから引き継ぐのは許可リストだけ(PATH やロケールなどの基本、プロキシと証明書の設定、モデルのプロバイダを選び認証する変数、ほとんどの ANTHROPIC_* と CLAUDE_CODE_* の設定、EVAL_*)。プラグインにツールチェーンの設定のようなほかのものを渡すには、EVAL_* 変数としてエクスポートする |
case.yaml のフィールド#
case.yaml は、prompt.md の代わり、または相棒で、ケースを YAML で記述し、他のファイルを指すフィールドを足します。schema_version: "1.1" と name が必要です。prompt.md のフィールドのうち、description・tags・plugins・runs・expected_outcome は最上位に、model・max_turns・timeout_seconds・allowed_tools・append_system_prompt・env は execution: の下に置きます。両方のファイルがあるときは、prompt.md のフロントマターが、対応する case.yaml のフィールドを上書きし、prompt.md の本文がプロンプトで、graders/*.md は case.yaml に並べたグレーダーのあとに足されます。次のフィールドは case.yaml にだけあります。
| フィールド | 目的 |
|---|---|
context.scaffold_script |
Claude が始まる前に、空の作業場所で動く、ケースのディレクトリの Bash のスクリプト。フィクスチャのファイルか git リポジトリを作る。--scaffold を渡したときだけ、最小限の環境と120秒の上限で動き、0 以外の終了は実行を失敗させる |
context.history_file |
再開する、ケースのディレクトリの .jsonl のトランスクリプト。ケースのプロンプトが次のユーザーのターンになる |
context.add_dirs |
実行中に Claude が読んでよい、ケースのディレクトリ内のディレクトリ。読み取り専用で許される |
execution.prompt |
ケース全体を case.yaml に置いて prompt.md を省くときの、プロンプト |
graders |
グレーダーのリスト。それぞれが name と、graders/*.md のフロントマターが取るのと同じキーを持つ。llm のグレーダーでは、採点基準を criteria に置く |
グレーダーのフロントマター#
graders/ の下のグレーダーのファイルは、どれも、種類ごとのオプションに加えて、次のキーをフロントマターに取ります。グレーダーの名前は、.md を除いたファイル名です。
| キー | 既定 | 目的 |
|---|---|---|
type |
必須 | グレーダーの種類のどれか |
weight |
1 |
実行の点数での相対的な重み。正の任意の数 |
arm |
未設定 | with-only は、2つのアームの実行でグレーダーを採点から外す。both は、Claude Code が外すはずのグレーダーを、両方のアームで採点させる |
regex のグレーダーは target を、llm のグレーダーは focus を取ります。どちらも同じ値を受け付けます。
| 値 | グレーダーが見るもの |
|---|---|
last_message |
Claude の最終応答のテキスト。既定 |
trace |
1行に1メッセージの JSON としてのセッション。regex のグレーダーはすべてのメッセージを、llm の判定は最初の12と最後の12を見る。中の引用符と改行は JSON エスケープされるので、正規表現は " でなく \" に合う |
files |
実行中に Claude が作ったパスのリスト(1行に1つ)。中身ではなく、用意のスクリプトが作ったものや、Claude が変更しただけのファイルも含まない |
{ source: file, path: <path> } |
実行後の作業場所の1つのファイルの中身。プラグインが作ったものを採点するのに使う。PNG・JPEG・GIF・WebP のファイルは、llm の判定に画像として見せられる。llm の判定は、.pptx や PDF のようなほかのバイナリのファイルを拒否するので、画像に描くか、テキストとして書き出してそれを採点する |
mock_calls |
モックした MCP ツールへの Claude の各呼び出しと、その入力、モックの答え |
グレーダーの種類と、通る条件は次のとおりです。
| 種類 | オプション | 通る条件 |
|---|---|---|
regex |
pattern・flags・match・target |
JavaScript の正規表現 pattern が対象に見つかる。match: not_contains で不在を、match: "count:N" でちょうど N 回の一致を求める。大文字小文字を区別しない指定は flags: i(インラインの (?i) は非対応) |
tool_used |
tool・input_match・min・max |
任意の input_match の正規表現に、JSON エンコードした入力が合う tool の呼び出しの数が、min(既定1)と max(既定は無制限)のあいだにある。ツールが一度も呼ばれなかったことを求めるには min: 0 と max: 0 を両方設定する |
tool_order |
before・after |
両方のツールが呼ばれ、before に合う最初の呼び出しが、after に合う最初の呼び出しより前にある。それぞれ、ツール名か { tool, input_match } |
file_exists |
path・exists |
Claude が作ったファイルが path の glob に合う(exists: false なら、どれも合わない)。実行中に作られたファイルだけが数えられる |
llm |
criteria・focus |
判定モデルが、採点基準に3票のうち少なくとも2票で PASS を出す。.md の配置では、ファイルの本文が採点基準 |
baseline |
baseline_file・criteria |
判定が、実行が、baseline_file(ケースのディレクトリの .jsonl)の参照のトランスクリプトと少なくとも同じ程度に基準を満たすと見る |
モックのファイル#
mocks/<server>/ の下の <tool>.md は、1つのツールに答えます。本文がツールの結果で、{{input.<field>}} と {{file:fixtures/<name>}} の置換を使えます。フロントマターは次のキーを受け付けます。
| キー | 既定 | 目的 |
|---|---|---|
type |
fixed |
fixed は本文を書いたまま返す。agent は、本文を、実行のあいだサーバーとして働く判定モデルへの指示として扱い、それは以前の呼び出しを履歴として見る |
expect |
未設定 | ドット区切りの入力のパスを、string・number・boolean・array・object のような型の名前、/regex/、リテラル、許すリテラルのリストのどれかに対応づけるマップ。違反する呼び出しは、実行を 0 点で中断し、サーバー・ツール・理由とともに aborted と報告される |
error |
false |
fixed だけ。本文をツールのエラーとして返す |
abort_when |
未設定 | agent だけ。エージェントが実行を中断してよい唯一の条件を並べた文章 |
サーバーのディレクトリのツールのファイルの隣には、任意の2つのファイルを置けます。
_server.md:複数のツールに答える、1つのtype: agentのモック。ツールはフロントマターのtools:キーに並べる。同じツールの<tool>.mdが優先する。expect:の守りは、ここでなく個々の<tool>.mdに置く_tools.json:本物のサーバーから保存したtools/listの応答。モックしたツールが、許容的なプレースホルダーでなく、本物の説明と入力スキーマを持つ
ケース自身の mocks/ ディレクトリは同じ配置で、スイートのモックをファイルごとに上書きします。
トラブル対処#
作者がよく出会う問題を、見えるものごとに並べます。
| 見えるもの | 原因と対処 |
|---|---|
plugin eval is currently in early access |
ビルドがこのコマンドの一般提供より前のもの。claude update を実行し、新しいセッションでもう一度動かす |
plugin eval is currently unavailable |
Anthropic がサーバー側でコマンドをオフにした。手元で戻せるものは無い。claude update を実行して、あとで新しいセッションでやり直す |
is not a trusted plugin directory, and this run cannot stop to ask you about it |
Claude Code がまだ信頼していないディレクトリへの最初の実行で、標準入力か標準出力が端末でないか --json を渡したので、尋ねられない。端末で一度 claude plugin eval <dir> を動かしてプロンプトに答えるか、プラグインのコードとスイートを信頼するなら --trust-plugin を渡す |
is too old for claude plugin eval |
PATH の git が 2.31 より古く、claude plugin eval は、ケースを動かす前に止まり、版を示すメッセージとともに 1 で終了した。実行のたびに Claude Code は、リポジトリの git の設定が起動できる git のフック・資格情報ヘルパー・他のプログラムをオフにするが、その環境の設定(GIT_CONFIG_COUNT)は git 2.31 から読まれる。古い git はその設定を無視するので、それらのプログラムが動きうる実行を採点せず、スイートが止まる。Git 2.31 以降を入れてやり直す(v2.1.283 より前は git の版を確認せず、古い git ではそれらがオンのまま動いた) |
No eval cases found |
有効な eval ディレクトリの下に <case>/prompt.md も <case>/case.yaml も無いか、--case と --tag の絞り込みがどのケースにも合わなかった。プラグインのルートから実行するか、claude plugin eval init でスイートを作る |
基準のアームでプラグインが無い、または Δ がゼロ |
要約に W/OUT の列が無い、またはケースが ablation requested but no plugin resolved で失敗するなら、たいていは、ケースのプラグインが見つからなかった。すべてのケースが context.history_file でトランスクリプトを再開するなら、その列の欠けは想定どおり(既定で1つのアームで動くため)。そうでなければ、ケースに、ケースのディレクトリからプラグインのディレクトリへのパスの plugins: ["../.."] を足す。プラグインが読み込まれたのに Δ がゼロ近くで tool_used: Skill のグレーダーが失敗するなら、たいていは本当の発見で、スキルの description がプロンプトの言い回しで発火していない。説明を直して、同じスイートをやり直す |
プラグインのエージェントで Agent type '...' not found |
既定では、各ケースはプラグインありとなしで動き、なしの実行がプラグインなしの基準になる。基準の実行で Claude がプラグインのエージェントを呼ぶと、Agent ツールの呼び出しが Agent type '<plugin>:<agent-name>' not found. Available agents: ... で失敗する(一覧は、プラグインなしで存在するエージェントだけ。サブエージェントの組み込みのもの)。Δ はプラグインありの実行を基準と比べるので、このエラーは想定どおり。JSON の結果では、基準の実行は cases[].arms.without にある。プラグインを読み込んだ実行では、allowed_tools に Agent を並べたケースが、my-plugin:code-reviewer のような名前空間つきの名前でプラグインのエージェントを呼べる。基準の実行を飛ばすには --ablation none |
| 正しいファイルができたのにすべて 0 点 | グレーダーが、ファイルの中身のつもりで、作られたパスのリストの files を対象にしている。target か focus に { source: file, path: <path> } を使う。別に、file_exists は実行中に作られたファイルだけを数えるので、用意のスクリプトが作ったものや、Claude が編集しただけのファイルは見えない。中身を採点するか、Edit に tool_used を使う |
| トレースへの正規表現が、見えているテキストに合わない | 対象を間違えている(既定の target は last_message で、トレースではない)。trace を対象にしたときは1行ずつの JSON なので、引用符は \" で出る。正規表現は JavaScript の構文なので、(?i) でなく flags に i を置く |
| ツールが拒否される、MCP ツールが無い、Bash が動かない | 読み取り専用のセット以外は許可が要る(--allow-tools Bash Write など)。自分の個人の MCP サーバーは実行に読み込まれない。プラグイン自身のサーバーは、オプトインしない限り起動せず、そのツールにも --allow-tools "mcp__plugin_<plugin>_<server>__*" の許可が要る(モックしたツールにはどちらも不要) |
実行が 1 で終わるのに結果は良さそう |
既定の --threshold が 1.0 なので、完全でないケースが1つでもあると 1 で終わる。求める点数に合うしきい値を設定する。読み込みに失敗したケースのファイルも 1 になり、それは表の上の標準エラーに報告される |
--json output path must end in .json |
--json の後ろに対象を置いたので、出力のパスとして読まれた。claude plugin eval . --json のように対象を先に置くか、--json に .json のパスを明示する |
点数 1.0 の実行の下で、あるグレーダーが passed: false を示す |
そのグレーダーは、2つのアームの実行で、設計上、点数から外されていて、scored フィールドが false。上の「プラグインなしの基準で採点する」を見る |
| 途中で使用量の上限かレート制限のエラーで実行が失敗する | スイートの実行中にアカウントがプランの使用量の上限か API のレート制限に達すると、以降の各実行がそのエラーで終わり、作ったもので採点され、たいてい 0 点になる。スイートは終わり、partial の印も付かないので、結果が劣化に見えうる。点数を信頼する前に、NOTES 列か JSON の cases[].arms.with[].error で上限のメッセージを確かめ、上限が戻ってから、--runs 1 か --case の絞り込みで抑えて、やり直す |
| 実行がタイムアウトする、ターンの上限に達する | 既定は10ターンと300秒。もっと要る作業には、ケースの max_turns と timeout_seconds を上げ、実行ごとの厳しい上限でなく、--max-cost-usd をコストの天井にする |
補足
プラグインのコスト・利用の計測はプラグインを作って配る、claude plugin eval の引数はプラグインのリファレンスにあります。
公式ドキュメント(英語)
2026年10月5日時点の内容をもとに、日本語でまとめています。