1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Claude Code 2.1.299入門、@参照の展開停止とplugin evalのAgent除外を実測

1
Posted at

はじめに

チャット欄で @config/.env.local のようにファイルを指したとき、その中身がどの時点でモデルに渡っているかを意識したことはあるでしょうか。@ メンションは手軽なぶん、指した時点でファイルの全文が会話に入ります。読ませるつもりのなかった行まで文脈に載り、セッションの記録にも残ります。

もう一つ、プラグインを claude plugin eval で評価していると、Claude がサブエージェントに仕事を回してしまい、プラグインそのものの振る舞いを測りにくい場面があります。

2026-10-14 に公開された Claude Code 2.1.299 には、この 2 つにそれぞれ効く変更が入りました。@ メンションでファイルの中身ではなくパスだけを渡す環境変数 CLAUDE_CODE_DISABLE_FILE_MENTIONS と、評価実行から特定の組み込みツールを外す claude plugin eval --disallow-tools です。本記事では、この 2 つの設定手順と、条件を変えて実際に動かした結果を紹介します。

対象読者は、Claude Code を業務で使っていて、機密を含むファイルの扱いやプラグインの評価・CI 組み込みに関心のある開発者です。

この記事で解決できること

  • @ で指したファイルの中身を自動で文脈に入れず、パスだけを渡す設定ができる
  • その設定をどこに書けば効き、どこに書くと無視されるかがわかる
  • claude plugin eval で Agent ツールを外して評価し、外したツールに依存する grader(採点ルール)を書き換えられる

前提条件と検証環境

  • Claude Code 2.1.299 以降(検証には同日公開の 2.1.300 を使いました)
  • claude -p(非対話モード)が認証済みで動く環境
  • 作業ディレクトリは、リポジトリの外に作った空のディレクトリ

実機で確かめたのは「CLAUDE_CODE_DISABLE_FILE_MENTIONS の有無による応答の違い」と「--disallow-tools の有無による評価結果の違い」の 2 点です。ケース側の disallowed_tools フィールド、終了時のセッション再開表示、gzip 圧縮、アイドル時の自動圧縮は検証しておらず、changelog と公式ドキュメントの記述として紹介します。

TL;DR

この記事を読むと、次のことができるようになります。

  • CLAUDE_CODE_DISABLE_FILE_MENTIONS=1 をシェルかユーザー設定で指定し、@note.txt の中身をモデルへ自動で渡さないようにできる(筆者の比較では、既定で中身の文字列を答えたプロンプトが、設定後は NOCONTENT を返しました)
  • claude plugin eval --disallow-tools Agent で、評価の全ケースから Agent ツールを外せる(Agent の呼び出しを採点するケースでは、score が 1.00 から 0.00 に、コストが $0.12 から $0.07 に変わりました)
  • 外したツールを前提にした grader を、実行時の警告を手がかりに「呼ばれていないこと」を確かめる形へ書き換えられる

2.1.299 と 2.1.300 で入った変更

公式 changelog の 2.1.299 と 2.1.300(どちらも October 14, 2026)から、本記事で扱う項目を抜き出しました。

版 区分 内容(changelog の記述を要約) 本記事での扱い
2.1.299 Added CLAUDE_CODE_DISABLE_FILE_MENTIONS:@ メンションしたファイルの内容ではなくパスを渡し、ファイルツールで読ませる 実測あり
2.1.299 Added claude plugin eval の --disallow-tools とケースの disallowed_tools フィールド:Agent などの組み込みツールを評価実行から外す フラグは実測あり・フィールドは未検証
2.1.299 Fixed API が拒否した実行を plugin eval が合格扱いにしていた不具合の修正 未検証
2.1.299 Changed 終了時に表示する再開コマンドが、セッション名ではなく ID でセッションを指す 未検証
2.1.299 Added アイドル時の自動圧縮(idle compaction)と、その閾値・無効化の設定 未検証
2.1.300 Changed テレメトリー無効時も、api.anthropic.com への大きなリクエストを gzip で圧縮 未検証

上の 2 行が本記事の中心で、残りは後半で簡単に紹介します。

手順の流れ

やりたいことに応じて、次のどちらかの流れになります。

手順 1:@ 参照の中身を渡さない設定にする

環境変数を設定する

環境変数リファレンスによると、CLAUDE_CODE_DISABLE_FILE_MENTIONS に 1 を設定すると、ファイルとディレクトリへの @ メンションが展開されなくなります。Claude は代わりに、メンションされたパスと「ファイルツールで読むように」という注記を受け取ります。v2.1.299 以降が必要です。

書く場所には制約があります。この変数は プロジェクト設定とローカル設定の env では無視されます。リポジトリに置いた .claude/settings.json に書いても効かないため、シェルの環境変数か、ユーザー設定・管理設定(managed settings)で指定します。

# シェルで指定する場合
export CLAUDE_CODE_DISABLE_FILE_MENTIONS=1

ユーザー設定(~/.claude/settings.json)に書く場合は、env に入れます。

{
  "env": {
    "CLAUDE_CODE_DISABLE_FILE_MENTIONS": "1"
  }
}

チーム全体で揃えたい場合は、リポジトリにコミットするのではなく、管理設定の側で配る形になります。

中身が渡っていないことを確かめる

設定の効き目を見るため、目印の文字列を 1 行だけ書いたファイルを用意し、環境変数の有無だけを変えて同じプロンプトを 2 回実行しました。読みやすいよう、プロンプトを変数に入れた形で載せます。

echo "SECRET_TOKEN_MARKER_ZEBRA42" > note.txt

PROMPT='@note.txt の中身の文字列をそのまま答えて。ツールは使わないで、入力に中身が含まれているかだけで答える。含まれていなければ NOCONTENT と答える'

# 既定
claude -p "$PROMPT"

# 環境変数あり
CLAUDE_CODE_DISABLE_FILE_MENTIONS=1 claude -p "$PROMPT"

既定では目印の文字列がそのまま返り、環境変数ありでは NOCONTENT が返りました。

条件 応答 読み取れること
既定 SECRET_TOKEN_MARKER_ZEBRA42 @note.txt の中身が入力に展開された
CLAUDE_CODE_DISABLE_FILE_MENTIONS=1 NOCONTENT 中身は入力に含まれていなかった

2 つの条件で起きていることを図にすると、次のようになります。環境変数ありの経路で渡る「パスと注記」は、公式ドキュメントの記述に基づくものです。

この比較には限界が 2 つあります。1 つ目は、「パスだけが渡った」ことをモデルの回答から間接的に確かめただけで、Claude Code が API に送ったリクエスト本体は観測していないことです。2 つ目は、「ツールは使わないで」がプロンプトでの依頼にすぎず、ツール自体は塞いでいないことです。既定のほうの回答は、仮にモデルが指示に反して Read を呼んでいたとしても同じになりえます。

2 つ目の点は、前回の記事 Claude Code 2.1.299入門、MCP許可ルールの一致範囲を実測した で別の角度から確かめています。そちらではツール呼び出し列を記録し、既定ではモデルが Read を呼んだ時点で「前回の Read から変わっていない」という応答が返ることを観測しました。モデルが読む前に、展開によって中身が読み込み済みとして扱われていた、という観測です。ツールを使わせない回答と、ツール呼び出し列という向きの違う 2 つの観測が、同じ結論を指しています。

なお、2.1.300 の changelog には、ローカルのセッション transcript に各 API リクエストのシステムプロンプト・ツール・パラメーターも記録するようになったと書かれています。展開の有無を transcript からもう少し直接に確かめられる可能性がありますが、筆者はまだ確認していません。

この設定で変わること、変わらないこと

CLAUDE_CODE_DISABLE_FILE_MENTIONS は、ファイルを読ませない設定ではありません。パスは引き続きモデルに渡り、Claude は必要と判断すればファイルツールで中身を読みます。変わるのは、中身が文脈に入るきっかけです。

観点 既定 CLAUDE_CODE_DISABLE_FILE_MENTIONS=1
@ を付けた時点で中身が文脈に入るか 入る 入らない
パス(ファイル名)がモデルに渡るか 渡る 渡る
中身が読まれる経路 展開(ツール呼び出しを経ない) ファイルツールの呼び出し

読ませたくないファイルを確実に守るには、この環境変数とは別に、権限設定の deny ルールでファイルツールの読み取りを塞ぎます。ファイル名そのものが機密にあたる場合(顧客名を含むパスなど)は、パスが渡る点にも注意してください。

手順 2:plugin eval から Agent ツールを外す

claude plugin eval の基本(prompt.md と graders/*.md の置き方、プラグインあり・なしの 2 アーム実行)は、以前の記事「Claude Code plugin eval 入門、--runs 1 でも2アームが走り実測0.118ドルでした」で扱いました。今回の検証は、case.yaml 1 ファイルで書いたケースで行いました。

claude plugin eval --help には、新しいフラグが次のように表示されます。

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

複数のツールを並べて指定でき、ケース側で許可していても全ケースから外す、という意味です。

最小プラグインとケースを用意する

検証には、プラグインの定義ファイルとケース 1 件だけの構成を使いました。

p1/
  .claude-plugin/
    plugin.json
  evals/
    c1/
      case.yaml

ケースの骨格は次のとおりです(プロンプトは要旨です)。

schema_version: "1.1"
name: c1
execution:
  prompt: "Agent ツールで subagent を起動。使えなければ NO_AGENT_TOOL と返答"
graders:
  - name: agent_used
    type: tool_used
    tool: Agent

case.yaml だけでケースを完結させる場合、検証では次の 4 項目のどれが欠けてもエラーになりました。

  • schema_version:ケース形式のバージョンで、公式ドキュメントでは "1.1" と書かれています
  • name:ケース名です
  • execution.prompt:prompt.md を置かない場合のプロンプトです。トップレベルではなく execution: の下に置きます
  • graders[].name:graders/*.md ではファイル名が grader 名になりますが、case.yaml に並べるときは name を明示します

grader の tool_used は、指定したツールの呼び出し回数が min(既定 1)以上 max(既定は上限なし)以下のときに合格します。このケースの grader は「Agent が 1 回以上呼ばれたら合格」という意味になります。

--disallow-tools なしで実行する

claude plugin eval ./p1 --ablation none --trust-plugin --no-publish

付けたオプションの役割は次のとおりです。

  • --ablation none:プラグインなしの比較用アームを走らせません。今回の確認はプラグインの有無に依存しないため片側だけにしました(公式ドキュメントでは、比較が不要な場面でコストが半分になると説明されています)
  • --trust-plugin:初回の信頼確認をスキップします
  • --no-publish:レポートを外部に公開せず手元に残します

--runs を指定しなかったため、ケースは 3 回実行されました(公式ドキュメントでも既定は 3 回です)。3 回とも、grader の行は次のとおりでした。

✓ agent_used: Agent called 1x

score は 1.00、表示されたコストは $0.12、所要時間は 14 秒でした。

--disallow-tools Agent を付けて実行する

claude plugin eval ./p1 --ablation none --trust-plugin --no-publish --disallow-tools Agent

出力の先頭に、除外したツールを示す行が出ます。

Removed from Claude's tools in every case (--disallow-tools): Agent

3 回とも Agent called 0x となり、score は 0.00、コストは $0.07 でした。あわせて、出力の NOTES に次の警告が出ました(抜粋です。... は省略箇所を示します)。

grader "agent_used" cannot pass: ... Agent is in the case's disallowed_tools or --disallow-tools ... invert it (max: 0) if absence is the point

2 つの条件を並べると次のようになります。

条件 Agent の呼び出し score コスト
--disallow-tools なし 1 回(3 回の実行すべて) 1.00 $0.12(14 秒)
--disallow-tools Agent 0 回(3 回の実行すべて) 0.00 $0.07

Agent ツールは確かに全実行から外れ、外したツールに依存する grader があることも、実行側が名指しで教えてくれました。

外したツールに依存する grader を書き換える

警告の趣旨は「Agent を外した状態では、Agent の呼び出しを求める grader は合格しない。呼ばれないことを確かめたいなら反転する」です。抜粋した範囲では max: 0 とだけ書かれていますが、公式ドキュメントの grader 表では min の既定値が 1 のため、一度も呼ばれないことを表すには min: 0 と max: 0 の両方を書くよう案内されています。

graders:
  - name: agent_not_used
    type: tool_used
    tool: Agent
    min: 0
    max: 0

この反転版の grader は、今回は走らせていません。ケースごとに外すツールを変えたい場合はケースの disallowed_tools フィールドを使う、と changelog にありますが、こちらも未検証です。

トラブルシューティング

Q1: case.yaml だけのケースがエラーで読み込まれない

A: schema_version・name・execution.prompt・graders[].name の 4 項目がそろっているかを確認してください。prompt をトップレベルに書いている、graders の各要素に name がない、の 2 つは、prompt.md と graders/*.md の書き方に慣れていると起こしやすい間違いです。

Q2: プロジェクトの .claude/settings.json に書いた CLAUDE_CODE_DISABLE_FILE_MENTIONS が効かない

A: 仕様どおりの挙動です。環境変数リファレンスによると、この変数はプロジェクト設定とローカル設定の env では無視されます。シェルの環境変数か、ユーザー設定・管理設定に移してください。

Q3: --disallow-tools を付けたらスイートが失敗扱いになる

A: 筆者が同じケースで --disallow-tools Agent 付きの実行をやり直したところ、終了コードは 1 でした(この回のコストは $0.06 で、実行ごとに数セントの揺れがあります)。公式ドキュメントによると、--threshold の既定値は 1.0 で、1 ケースでも満点を下回るとコマンドは終了コード 1 で終わります。CI に組み込んでいる場合、今回の agent_used のような矛盾した grader が 1 つあるだけでジョブが落ちます。NOTES に cannot pass の警告が出ていないかを確認し、該当する grader を反転するか外してください。

同じリリースのほかの変更(changelog の記載のみ・未検証)

以下は検証しておらず、changelog と環境変数リファレンスの記述だけで紹介します。

  • 終了時の再開コマンド(2.1.299):セッション名ではなく ID でセッションを指すようになりました。表示された行を貼り付けたときに、セッション名に含まれる文字列が実行されないようにするための変更です
  • gzip 圧縮(2.1.300):テレメトリーを無効にしていても、api.anthropic.com への大きなリクエストが gzip で圧縮されます。リファレンスによると圧縮は直接接続のときだけで、プロキシ経由やクライアント証明書・NODE_EXTRA_CA_CERTS の設定時は行われません。TLS 検査プロキシが圧縮済みリクエストを扱えない場合は CLAUDE_CODE_GZIP_REQUEST_BODIES=0 で無効化します
  • アイドル時の自動圧縮(2.1.299):設定リファレンスの条件(1 時間のプロンプトキャッシュを使っている、スリープ中でない、など)を満たす場合に、ターミナルで 200K トークン以上の会話を約 54 分放置すると、1 時間のプロンプトキャッシュが切れる前に圧縮されます。閾値は CLAUDE_CODE_IDLE_COMPACT_MIN_TOKENS(既定 200000・100000 未満は 100000 に引き上げ)で変えられ、settings.json の "idleCompaction": false で無効化できます。どちらも v2.1.290 以降が必要です
  • plugin eval の API エラー(2.1.299):API エラーで終わった実行は採点されずに 0 点となり、スイートは終了コード 1 で終わるようになりました。利用上限などで途中終了した実行が、CI で合格として素通りしなくなります

実測してわかったこと

手を動かしてみて、筆者が気づいた点を 4 つ挙げます。

1 つ目は、@ の展開を止めても、ファイルが読まれなくなるわけではない ことです。この環境変数が変えるのは中身が文脈に入るきっかけで、読むかどうかはモデルのツール呼び出しに移ります。そのぶん読み取りが権限ルールやフックの目に触れる場所へ出てくる、というのが筆者の受け取り方です。加えて、プロジェクト設定では無視されるため、リポジトリにコミットして全員に強制する使い方はできません。チームで揃えるなら管理設定の側の仕事になります。

2 つ目は、確かめられたのは間接観測まで という点です。claude -p の出力から見えるのはモデルの最終回答で、API に送られたリクエスト本体ではありません。今回はツールを使わせない回答で、前回はツール呼び出し列で確かめ、向きの違う 2 つの観測が一致しました。それでも断定はせず、2.1.300 で記録が増えた transcript を次の確認手段として考えています。

3 つ目は、--disallow-tools は環境の制約で、grader は振る舞いの主張 だという点です。Agent を外した状態で「Agent が呼ばれていない」を確かめる grader を置いても、必ず合格する確認にしかなりません。プラグイン単体で結果を出せるかを見たいなら、Agent を外したうえで最終回答や生成ファイルを採点します。Agent に逃げないことを CI で守りたいなら、Agent は外さずに min: 0 と max: 0 の grader を置きます。実行側が NOTES で矛盾を指摘してくれても score は 0.00 のまま出るので、score だけでなく NOTES まで読むのが安全です。

4 つ目は、この小さなケースではコストが 4 割ほど下がった ことです。$0.12 から $0.07 への差は $0.05 で、約 42% の減少でした。サブエージェントの起動に使われていたトークンがなくなったためと筆者は推測していますが、ケース 1 件・実行 3 回の結果なので、一般的な削減率としては扱っていません。

おわりに

CLAUDE_CODE_DISABLE_FILE_MENTIONS は、@ で指したファイルの中身を自動で文脈に入れないための設定で、書く場所はシェルかユーザー設定・管理設定に限られます。--disallow-tools は評価から組み込みツールを外すフラグで、外したツールに依存する grader は NOTES の警告を手がかりに書き直します。まずは @ を多用する手元のセッションで、環境変数の有無だけを変えて同じプロンプトを流し、応答の違いを一度確かめてみてください。

関連記事

参考リンク

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?