mcpField
T
test-harness

test-harness

github.com/zernieテスト・品質152.1k 回インストール2 日前に更新
リポジトリ

test-harness について

Claude Code の hooks、skills、設定、CLAUDE.md を一体のハーネスとしてテストするスキルです。単体、決定論的、実モデル評価の各段階から、目的に足りる最小コストの方法を選びます。

主な機能

  1. 01単体・決定論的・評価の段階を選択
  2. 02フックのロジックと接続をテスト
  3. 03コンテキスト伝達とスキル起動を確認
  4. 04vigiles CLI でテストを実行
  5. 05評価のロックと CI 設定を案内

活用シーン

  1. 01フックがイベントを拒否・許可するか検証
  2. 02注入したコンテキストのモデル到達を確認
  3. 03スキル起動の適合率と再現率を測定
  4. 04ハーネス変更前後の Agent の動作を比較

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/zernie/vigiles --skill test-harness

インストール後、Claude Code で/test-harnessを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
cost-and-expectations.md
observing-a-run.md
writing-tests.md

詳細

Claude Code のハーネス(エージェントの動作を制御するフック、スキル、設定、CLAUDE.md)を、実際に出荷される組み立て済みの仕組みとしてテストします。vigiles にはコストの低い順に 3 つのティアがあります。このスキルが適切なティアを選び、テストを作成して実行します。

基本原則は、質問に答えられる最も低コストのティアから始め、本当に答えられない場合にだけ上のティアに進むことです。 3 つのティアのうち 2 つはモデルも API キーも不要なため、すべてのコミットで無料で実行できます。有料の実モデルティアを使うのは、質問に実モデルが本当に必要な場合だけです。

Step 0 — ティアを選ぶ(判断が必要なところ)

テスト対象に合わせて、質問に答えられる最も低コストのティアを選びます。

テスト対象ティアコストAPI
「このフックはイベント X をブロック/許可するか?」— 純粋なフックロジック、すべてのイベントタイプ(Edit/Write、PreCompact、SessionEnd、SubagentStop を含む)Unit無料、数ミリ秒、claude 不要runHook
「フックは組み立て済みのプラグインに実際に組み込まれていて、実際のセッションで発火するか?」Deterministic無料、API キー不要(実際の claude + スクリプト化されたモック)runHarnessTest + scriptModel
「注入されたコンテキスト(SessionStart フックや /command)は実際にモデルに届いたか?」Deterministic無料、API キー不要runHarnessTest → trace.modelRequests / assertRequestContains
「このスキルの説明は、必要なときに起動し(再現率)、不要なときは起動しないか(適合率)?」Eval有料(実モデル)measureTriggerRate(+ irrelevantPrompts)→ assertTriggerRate({ min, maxFalsePositive })
「より低コストのモデルで起動を測定し、下限値として信頼できるか?」Eval有料(2 回実行)compareContainment(weak, strong) → formatContainment
「この特定のスキルの出力は十分に良いか?」— オン/オフのベースラインなしで絶対的な品質を測定(単一スキルのテストではこちらが標準)Eval有料(実モデル)measure({ checks: [judged(rubric)] }) → assertRates({ min })
「このハーネスの変更によって、オフの場合と比べてエージェントの動作は変わるか?」— A/B の向上、リグレッション、シグナル対ノイズEval有料(実モデル)runEval(arms)+ assertSignificant

ハーネスに関する質問のほとんど(ブロック/許可、組み込み、コンテキスト到達)にモデルは不要です。Eval ティアが必要なのは、「モデルが起動するか/異なる動作をするか」という質問だけです。 ⚠️ すべてのプロンプトで発火率が 0%なら、反証されるまでは配線の不具合と考えてください。 説明文に対する評価のように見えますが、3 つの別々のセットアップミスが原因で発生します。fired に、名前空間付きの <plugin>:<skill> が必要なところに単独の ID を指定していること、.claude/skills のように単独で存在するディレクトリには**skillsDirが必要なのに pluginDir を指定していること、そしてfixture**がないことです。実行は空のディレクトリで始まるため、存在しないファイルについてのプロンプトは、モデルが正当に拒否するケースです。報告する前に、この 3 つすべてを除外してください。(一部のプロンプトだけが発火するなら、それは実際の数値です。疑って見直す必要はありません。)

より安価なモデルを基準に調整する前に、それが本当に下限かどうかを確認してください。 compareContainment(weak, strong) で確認できます。弱いモデルでは発火したものの強いモデルでは発火しなかったプロンプトが報告されます。該当するものがあれば、弱いモデルは下限ではなく、_別のルーター_です。強いモデルでのみ発火したプロンプトは想定どおりであり、失敗ではありません。1 回の測定(21 個のスキル、84 個のプロンプト、haiku 対 sonnet)では、弱いモデルのみで発火したものが 3 件あり、haiku のほうが高いスキルが 1 件ありました。そのため包含関係は確認できず、下限は維持されます。

unit と deterministic の両方の層で回答できる場合は、unit を優先してください。より高速で、deterministic のモックでは発生させられないイベントにも対応できます。

ステップ 0.4 — 実行の観察方法とその費用

それぞれ異なる質問に対応するリファレンスがあります。推測せず、必要なほうを開いてください。

  • 「実行では実際に何が行われましたか?」 — 呼び出されたツール、宣言した allowed-tools の範囲内に収まっていたか、書き込まれた内容、実行せずに呼び出しを記録する方法 → references/observing-a-run.md
  • 「無料、低価格、それともコンテナが必要ですか?」 — 3 つの区分と、有料の実行後にユーザーに伝える内容 → references/cost-and-expectations.md

2 つ目の確認を済ませずに「テストしてみます」と言ってはいけません。

ステップ 1 — vigiles がインストールされていることを確認する

vigiles が依存関係(package.json)に含まれているか確認し、なければ開発用依存関係としてインストールします。

npm i -D vigiles    # or: pnpm add -D vigiles / yarn add -D vigiles

deterministic 層には、PATH 上の claude CLI も必要です(API キーは不要です)。 npm i -g @anthropic-ai/claude-code。eval 層にはモデル認証が必要です。 claude CLI がなくても、unit 層のテストは作成して実行できます。

ステップ 2 — テスト対象のハーネスの範囲を特定する

次の順に、プロジェクトが実際に提供しているものを探します。

  1. .claude/settings.json / .claude/settings.local.json — インラインの hooks。
  2. .claude-plugin/plugin.json — プラグインマニフェスト(hooks、skills、agents、mcpServers)。
  3. hooks/hooks.json — プラグインの hooks 規約(例:obra/superpowers)。
  4. skills/<name>/SKILL.md、agents/<name>.md、commands/<name>.md。

具体的に 1 つ選んで特定します。たとえば、特定の PreToolUse hook、特定の SessionStart インジェクション、特定のスキルです。

ステップ 3 — 選んだ層のテストを書く

各層のひな形と、失敗を気付かれないまま握りつぶす 1 つのミス(手書きのランナーが stderr を飲み込む)については、 references/writing-tests.md を参照してください。

ファイルを書く前に読んでください。ひな形は層ごとに異なり、ランナーに関する警告を見落とすと、デバッグに多くの時間がかかります。

ステップ 4 — 実行する

ランナー(node:test / vitest / jest)では、テストは通常の非同期関数です。 または、セットアップ不要の CLI を使って、ファイルを検出して実行できます。

npx vigiles test                 # *.harness.{mjs,ts} — unit + deterministic, no API key
npx vigiles eval --trials=6      # *.eval.{mjs,ts} — real model (local / nightly, not CI)

unit 層の runHook テストには claude は不要で、必ず実行できます。claude がインストールされていなくても、テストを書いて実行してください。実際に実行できない層は、明確な ⊘ SKIPPED として報告されます(別途集計され、偽の ✓ にはなりません)。単独のスクリプトでは、vigiles の skip(reason) を使ってスキップを出力できます。スキップはデフォルトで合格扱いになりますが、機能が利用可能であることを検証する CI ジョブでは、スキップした層を失敗扱いにするため vigiles test --no-skip を実行してください。スキップありで緑になっても、未テストの範囲が残っています。unit と deterministic のテストは CI で実行し(無料)、eval は認証情報を用意してローカルまたはスケジュール実行してください。

CI — 手順を手書きしないでください

これらのティアは CI に組み込むもので、そのための公開済み Action があります。vigiles init を実行すると、.github/workflows/vigiles.yml が作成され、Action(zernie/vigiles@v1)を利用できるジョブに設定するとともに、このティア用のプレーンな npx vigiles test ジョブも設定されます。このジョブにはリポジトリローカルの node_modules が必要ですが、Action はそれをインストールしないため、意図的に手書きのままにしてあります。

リポジトリにすでにワークフローがある場合は、Action の入力について docs/github-action.md に説明があります。推測せず、そちらを確認してください。入力一覧は action.yml で定義されており、ここに同じ内容を載せると、気づかれないまま古くなる二つ目の情報源になってしまいます。まさにこのファイルの姉妹ドキュメントと、利用者の CI コメントの両方で起きたことです。いずれも 2026-08-18 に確認されています。

Step 5 — CI の信頼性を保つため、eval をロックする(自動で行います)

実モデルの eval はユーザーのサブスクリプションを使って実行します。ローカルでのみ実行し、CI では実行しません。そのため、**eval を作成する際に、その結果をユーザーがいつでも確認できるよう最新に保ちます。**頼まれなくても、次の 2 つを行ってください。

  1. **すべての eval に name を付けます。**ロックキーとして使われます。

  2. 実行後にロックをコミットします。

    vigiles eval --update      # records the result → .vigiles/eval-locks/<name>.lock.json
    

    続いて、そのファイルをコミットします。CI では vigiles eval --check(モデルは使用しません)を実行して、入力との一致を確認します。そのため、後から再 eval を忘れて編集した場合は、古い数値のままリリースされるのではなく、明確に失敗します。

**後でスキルの説明やプロンプトを変更した場合は、vigiles eval --update を再実行して、更新したロックをコミットしてください。**変更によって eval の測定対象が変わるためです。(vigiles からも通知があります。ロックが存在する場合、SKILL.md の編集時にブロックされないリマインダーが表示されます。)

低コストで済む理由:--check は入力(スキルのテキスト、プロンプト、モデル)のハッシュ化のみを行います。テストの しきい値 を変更した場合は保存済みの数値を再利用するため、モデルは不要です。新しい --update が必要なのは 入力 が変更された場合だけです。詳しい仕組みについては、 docs/harness-testing.md を参照してください。

ユーザーがテスト対象を指定していない場合

指定するようユーザーに尋ねず、**実際に役立つテストを選んで実演してください。**ハーネスの対象範囲(Step 2)を調べ、意味のあるテストのうち最も低コストなものを選び、作成して実行し、結果を示します。おすすめの既定値は次のとおりです(上から優先)。

  1. PreToolUse フック → 意図した対象をブロックし、安全な関連ケースは許可することを 単体テスト します。
  2. コンテキストを注入する SessionStart フック → テキストが実際にモデルに届くことを 決定論的テスト します(assertRequestContains)。
  3. スキル → pluginDir 経由で解決されることを 決定論的テスト し、追加で有料の measureTriggerRate eval を提案します。

どのティアを使ったか、その理由とともに説明し、より低コストなテストでは質問に十分答えられない場合は、上位のティアを試すことを提案してください。

参考資料

すべてのティア、実際のスキルのテスト方法、「発火した ≠ 反映された」という考え方、安全性を既定とするサンドボックス、カバレッジマトリクス、promptfoo との比較を含む完全なガイドは、 docs/harness-testing.md にあります。

コメント