Claude Media
claude plugin evalの--disallow-toolsでAgentを評価から外す

claude plugin evalの--disallow-toolsでAgentを評価から外す

v2.1.299で入った--disallow-toolsとdisallowed_toolsは、Agentなどの組み込みツールを評価実行から外す仕組みです。--allow-toolsとの違いと使いどころを解説します。

claude plugin evalの--disallow-toolsは、Agentのような組み込みツールを、評価の全ケースでClaudeから取り上げるフラグです。ケース側には同じ役割のdisallowed_toolsフィールドがあります。どちらもv2.1.299で入りました。

--allow-toolsが「許可を足す」側なのに対し、こちらは「許可されていても使わせない」側です。プラグインの本体であるスキルやフックの動きを測りたいのに、Claudeがサブエージェントへ丸投げして結果が曖昧になる、という状況で効きます。

--disallow-toolsは何をするフラグか

claude plugin eval --help(v2.1.301で確認)の説明は次のとおりです。

Built-in tools to keep from Claude in every case, even if granted (e.g. Agent TaskStop)

要点は2つあります。

  • 対象は組み込みツールです。例にはAgentとTaskStopが挙がっています
  • 「even if granted」とあるとおり、--allow-toolsやケースのallowed_toolsで許可していても、外す指定が優先されます

v2.1.299の変更履歴には「--disallow-toolsとdisallowed_toolsのケースフィールドを追加。Agentなどの組み込みツールをevalの実行から外す」とあります。フラグは全ケースに一括で、フィールドはケース単位で効く、という分担です。

claude plugin eval . --disallow-tools Agent TaskStop

複数のツールはスペース区切りで並べます。--allow-toolsと同じく値を複数取る形なので、ターゲットは先に書きます。ターゲットを後ろに置くと、直前のオプションの値として読まれる恐れがあります。公式の手引きは--tag・--allow-tools・--jsonについて同じ注意を書いています。--disallow-toolsも同じ複数値の形ですが、この注意が明記されているわけではありません。

なぜAgentを外す場面があるのか

evalの実行では、ケースのallowed_toolsに書いた読み取り専用ツールだけが使えます。公式の手引きによると、その候補は次の一覧です。

  • Read / Glob / Grep / NotebookRead
  • Skill / AskUserQuestion / Agent / TodoWrite
  • タスク系のTaskCreate / TaskGet / TaskList / TaskUpdate / TaskStop

Agentはこの読み取り専用セットに含まれています。ケースがallowed_toolsにAgentを書けば、Claudeはサブエージェントを呼べます。ここに判断の分かれ目があります。

Agentが残ると測りにくくなる場面

手引きには、Agentに関わる挙動が2つ載っています。

  1. プラグイン付きの実行では、Agentを許可したケースがプラグインのエージェントをmy-plugin:code-reviewerのような名前空間付きで呼べます
  2. プラグインなしのベースライン実行では、同じ呼び出しがAgent type '<plugin>:<agent-name>' not foundで失敗します。公式はこれを想定どおりの挙動としています

つまり、プラグインのエージェントを呼ぶこと自体が評価の対象なら、Agentは残すべきツールです。逆に、スキルの手順そのものを測りたいケースでは、Claudeが作業をサブエージェントに任せると、トランスクリプトの上で手順が追いにくくなります。tool_usedのgraderは呼び出しの回数と入力を数えるので、肝心の作業がサブエージェントの内側に隠れると、親の視点ではAgentが1回呼ばれたことしか見えない可能性があります。この点は公式の記述から組み立てた見立てで、挙動として保証された説明ではありません。

外す理由は、おおむね次の2系統に整理できます。

目的Agentの扱い理由
プラグインのエージェント連携を測るAgentの扱い残す(allowed_toolsに書く)理由名前空間付きの呼び出しが評価対象そのもの
スキルやプロンプトの手順を測るAgentの扱い外す(--disallow-tools Agent)理由作業をClaude自身にやらせ、手順をトランスクリプトに残す
実行の暴走や費用を抑えるAgentの扱い外す理由サブエージェントの追加実行を防ぐ

3行目は一般的な見立てです。公式の文面は、外す目的を限定していません。

ケース単位のdisallowed_tools

フラグが全ケース共通なのに対し、disallowed_toolsはケースごとに外すツールを変えたいときに使います。たとえばAgent連携を測るケースだけAgentを残し、ほかのケースは外す、という構成です。

ここで注意が要ります。手引きのprompt.mdフロントマターの表と、case.yamlの説明に載るフィールドは、allowed_toolsなどの一覧までです。disallowed_toolsはその一覧に出てきません。さらに手引きは「prompt.mdの未知のキーはエラー」と書いています。

そのため、このフィールドをどこに書くか(prompt.mdのフロントマターか、case.yamlのexecution:の下か)は、公式の手引きの表からは読み取れません。変更履歴にあるのは「ケースフィールドを追加」という一行だけです。試すときは、まず1ケースだけでclaude plugin eval <ケースのファイル>を実行し、スキーマ違反のエラーが出ないかを見るのが安全です。ケース単体の指定は、手引きにあるprompt.mdかcase.yamlのファイルを直接渡す方法です。

迷うあいだは、確実に動く--disallow-toolsフラグで全ケースに掛けておく手があります。

--allow-toolsとの組み合わせ

ツールの出入りを決める指定は3層あります。

指定届く範囲扱えるツール
ケースのallowed_tools届く範囲そのケース扱えるツール読み取り専用セットのうち、使いたいもの
--allow-tools届く範囲実行の全ケース扱えるツールBash・Write・Editなど、既定で取り上げられるもの
--disallow-tools届く範囲実行の全ケース扱えるツール許可済みかどうかを問わず、外したいもの

分かれ目は、外す指定が許可より後ろで効くことだけです。AgentがBashのように「許可されないと使えない」ツールではなく、読み取り専用セットに最初から入っているため、allowed_toolsに書かなければ使えず、書いても--disallow-toolsで消せます。

切り分け

Agentが呼べるかを決める順番

  1. Q`--disallow-tools`にAgentを指定していませんか?
    答えが指定している

    allowed_toolsにAgentを書いていても、このケースを含む全ケースでAgentは呼べません。

    答えがはい
  2. Qケースの`allowed_tools`にAgentを書いていますか?
    答えが書いていない

    Agentは取り上げられたままです。ケースが求めると、進行表示にnot grantedと出ます。

    答えがはい

Agentを呼べる

プラグイン付きの実行では、my-plugin:code-reviewerのような名前空間付きの呼び出しが通ります。

--disallow-toolsで外したツールがどう表示されるかは、手引きに記載がありません。外したのにケースの手順がそのツールを前提にしていると、その手順が成立しません。評価結果が下がったときは、外したツールが原因かどうかを疑う価値があります。

claude plugin eval . \
  --allow-tools Write Edit "Bash(npm test *)" \
  --disallow-tools Agent

Bashを許可するとOSレベルのサンドボックス内で動く点は変わりません。サンドボックスの前提はclaude plugin evalの使い方にまとめています。

ベースライン実行との関係(--ablation)

既定では、各ケースがプラグイン付きとプラグインなしの2系統で走ります。プラグインなしがベースラインで、スコアの差がΔです。--ablationで、この比較を取るかどうかを選びます。

--ablation動き
none動き1系統だけ走らせる。比較が要らないとき、費用が半分になる
with-without動きベースラインを足して比較する

allowed_toolsにAgentを書いたケースでは、ベースラインの側でプラグインのエージェントを呼ぶ呼び出しが失敗します。前の節のAgent type ... not foundです。Δはこの失敗を含んだ差なので、エージェント連携を測るケースではAgentを残したまま読みます。

ケースを1つに絞って--disallow-toolsの効き方を確かめるときは、比較を止めると費用も時間も抑えられます。手引きにも、--case・--runs 1・--ablation noneを組み合わせて1ケースだけ回す例があります。

claude plugin eval . --case <ケース名> --runs 1 --ablation none --disallow-tools Agent

--disallow-toolsを足した実行で、プラグイン付きとなしの両方にその制限が掛かるかは、手引きに明記がありません。Δを比べるときは、制限の有無を揃えた実行どうしで見るのが安全です。

Agentが呼ばれていないことをケース側で確かめる

フラグで外した結果、本当にAgentが一度も呼ばれていないかは、tool_usedのgraderで確かめられます。手引きによると、ツールが一度も呼ばれなかったことを求めるには、min: 0とmax: 0を両方指定します。

---
type: tool_used
tool: Agent
min: 0
max: 0
---

これをevals/<ケース名>/graders/no-agent.mdのようなファイルに置きます。graderの置き場所は、手引きのskill-fired.mdの例と同じ形です。Agentを残した実行では呼び出しが起きるので、このgraderは落ちます。外す設定が効いているかどうかの目印として使えます。

CIで使うときの考え方

CIでは、モデルを固定し、--trust-pluginと--jsonで結果を残し、終了コードで判定する構成が基本です。この枠にそのまま--disallow-toolsを足せます。

claude plugin eval . \
  --trust-plugin \
  --json results.json \
  --threshold 0.8 \
  --model claude-sonnet-5 \
  --no-publish \
  --disallow-tools Agent

CIの合否とaggregate-result.jsonの読み方はclaude plugin evalをCIの合否に使うで扱っています。ここで押さえておきたいのは、ツールの制限もスコアの比較条件の一部だという点です。ある日から--disallow-toolsを足すと、過去の実行と同じ条件ではなくなります。モデルを固定する理由と同じで、ツールの制限も変えたら、変えた時点を境に推移を見直す必要があります。

つまずきやすい点

  • Agentを外すとエージェント連携のケースが落ちる: my-plugin:code-reviewerのようにプラグインのエージェントを呼ぶケースは、Agentが無いと成立しません。フラグは全ケースに掛かるので、連携ケースが混ざるスイートでは使いにくくなります
  • ベースラインの失敗と混同する: プラグインなしの実行でAgent type ... not foundが出るのは、外した結果ではなく想定どおりの挙動です。原因を取り違えないために、--ablation noneでベースラインを止めて切り分けます
  • v2.1.299より前のClaude Codeでは通らない: フラグはその版で入りました。claude --versionで確かめます。モックやフィクスチャを併用するならフィクスチャとモックの使い方も合わせて確認できます

このフラグが入ったリリースの全体像はv2.1.299のリリースノートに載っています。

まとめ

--disallow-toolsは、評価で測りたい動きをClaude自身にやらせるための絞り込みです。Agentを外すと、サブエージェントへの委譲が起きなくなります。委譲そのものを測るなら残します。ケース単位のdisallowed_toolsは、手引きのフィールド表に載っていないため、書き場所は1ケースで試してから広げるのが確実です。サブエージェントの仕組み自体はClaude Code Subagents完全ガイドで扱っています。

この記事を共有:XはてブLinkedIn