harness-tour について
harness-tour は、違反操作を意図的に試し、hook によるリアルタイムの阻止を示す Claude スキルです。短縮版と全ルール版があり、終了時にデモファイルを削除して監査記録を残します。
主な機能
- 01R1~R3の短縮版とR1~R10の全ルール版
- 02開始前のハーネス状態チェック
- 03hook が阻止した理由の表示
- 04デモファイルと対応する索引行の削除
- 05監査記録による実行結果の提示
活用シーン
- 01プロジェクトメンバーへのルール違反阻止の実演
- 02Claude セッションでプロジェクトのhookが読み込まれたか確認
- 03全ルール版で阻止・記録・通知の動作を確認
MCP 対応
このスキルはホストのhookでルール適用を実演するもので、MCP サーバーではありません。README ではhookとMCPを区別しています。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ rheinmir/ setup --skill harness-tourインストール後、Claude Code で/harness-tourを入力して読み込まれたか確認します。
詳細
スキル:harness-tour
WHAT
目的とコンテキスト
- 目的: harness の動作をユーザーに読ませるのではなく、実際に見せます。あなた、つまり Claude が実際のプロジェクトで意図的にルールに違反し、フックにリアルタイムでブロックされる様子を実況します。最後にゴミを残しません。
- トリガー(使用するタイミング): ユーザーが
/harness-tourを入力するか、「harness tour」「harness の動作を見る」「test short」「test full」と言ったとき(disable-model-invocation: true— ユーザーが呼び出した場合にのみ実行)。長さは 2 種類です。SHORT(デフォルト、R1·R2·R3)と FULL(R1–R10)。 - 対象外: harness のインストールや修正はしません(MISSING の場合にインストールコマンドを提案するのみ)。フックがない場合に演技はしません。プロジェクトの既存ファイルには触れません。
demo.sh/test-broad.shは置き換えません(機械的なデモにはセッションが不要なため)。
メンタルモデル
ARGUMENTS → 長さ(SHORT|FULL)→ harness の事前確認(POC|PROD|MISSING)→ 各シーン:実況 → 1 つのルールに対応するパスマップ上で意図的に違反 → フックがライブでブロック → 原文を引用 → 修復 → tour-demo* と同じ作業内のインデックス行をクリーンアップ → audit.jsonl の引用で締めくくり。ルールは 3 グループです。ライブでブロック(R1,R2,R3,R5,R7,R9)· 記録/警告のみでブロックしない(R4,R8,R10)· リポジトリ層(R6)。
入力と出力の契約
| フィールド | 必須? | 意味 | |
|---|---|---|---|
| In | ARGUMENTS | いいえ | full / 10 / "đầy đủ" を含む → FULL。それ以外 → SHORT |
| In | harness がインストール済みのプロジェクトルートで開始したセッション | はい | .claude/settings.json が読み込まれている必要があります。そうでない場合は MISSING |
| Out | 実況 + 各シーンでブロックした stderr の原文引用 | はい | 例:[R1 no-write-raw] …、[R3 index-sync] … |
| Out | クリーンなプロジェクト | はい | PASS したすべての tour-demo* と、対応するインデックス行を削除します。harness の成果物は保持します |
| Out | 締めくくり | はい | 直前にブロックしたルールを要約し、.claude/audit/*.jsonl の末尾数行を cat で表示します。FULL では 10 個のルールの表も追加します |
ルールと機能
- RULE-01(必須):各シーンは、実況 → 違反 → ブロック理由を原文で引用 → 修復、の順です。省略してはいけません。
- RULE-02(必須):
tour-demo*という名前のファイルだけに触れます。プロジェクトの既存ファイルは絶対に変更/削除しません。 - RULE-03(必須):本来ブロックされるべきシーンがブロックされなかった場合 → ツアーを中止し、「ルール X のガードレールが壊れています」と報告します。これは対処が必要な実際のバグです。 (ブロックしないグループの R4/R6/R8/R10 には適用しません。これらはもともとブロックしません。)
- 機能:
llmwiki/内のデモファイルtour-demo*の作成/削除 +wiki/index.mdの編集(デモ行)、監査成果物の読み取り、ローカル harness スクリプトの実行。ホストのフック(PreToolUse/Stop)に依存します。フックがなければ演技はしません。
失敗時の境界
- 事前確認で何も表示されない → ブロック(MISSING):停止し、PoC のインストールコマンドと、プロジェクトルートで新しいセッションを開くよう提案します。演技はしません。
- 本来ブロックされるべきシーンがブロックされなかった → 失敗:ツアーを中止し、「ルール X のガードレールが壊れています」と報告します(R4/R6/R8/R10 を除く)。
- クリーンアップでファイルを削除したものの、インデックス行が残っている → Stop フックの R3 がそのクリーンアップ処理をブロックします。残った行を同じ作業内で削除してから終了します。
HOW
メインワークフロー
| ステップ | 種類 | 入力 | アクション | 出力/終了 | 失敗時/次の処理 |
|---|---|---|---|---|---|
| W01 | 決定論的 | ARGUMENTS | ツアーの長さを選択 | SHORT または FULL | — |
| W02 | 決定論的 | ルートセッション | harness の事前確認(下記の grep / test コマンド) | POC / PROD | 何も表示されない → MISSING、停止 |
| W03 | 副作用あり | パス → ルールの対応付け | SHORT(3 シーン)または FULL(R1–R10)のシナリオを順番に実行し、各シーンの前に実況する | ブロックした stderr の原文引用 + PASS ファイル | ブロックされなかった場合は停止し、ガードレールの破損を報告 |
| W04 | 副作用あり | PASS 済みの tour-demo* ファイル | 同じ作業内でクリーンアップ:ファイルとインデックス行を削除 | クリーンなプロジェクト | Stop R3 がブロックした場合は、残った行を削除 |
| W05 | 決定論的 | audit | 締めくくり:ルールを要約し、.claude/audit/*.jsonl を cat で表示 | レポート | — |
各ステップの詳細(W01–W05 の信頼できる情報源):
ツアーの長さを選択(ARGUMENTS を読み取る)
full/10/ "đầy đủ" を含む → FULL(R1–R10)。- それ以外(デフォルト、または
short/3)→ SHORT(3 シーン:R1 · R2 · R3)。
事前チェック — セッション内で稼働しているハーネスを検出します
セッションの ROOT で実行します:
{ grep -q llmwiki-validate .claude/settings.json 2>/dev/null && test -f harness/poc-vendor-neutral/bin/llmwiki-validate.py && echo POC; }
test -f llmwiki/.claude/hooks/pre_tool_use.py && echo PROD
POCと表示された場合 → メインの方法です。PoC は現在 R1~R10 に対応しています(PreToolUse でブロックする 5 つのルール+イベントフック経由の R3/R4/R8/R10)。PRODと表示された場合 → 本番用ハーネスです。R1~R10 と、以下の short/full シナリオは同じです。異なるのは フックスクリプト名 (pre_tool_use.py/post_tool_use.py/stop.py)と、R1 がpermissions.deny経由でブロックされる場合がある点だけです。同じように実演できます。- 何も表示されない場合 → MISSING。停止してください(実演しないでください)。インストール方法を案内します(メインの方法は PoC です):
その後、そのプロジェクトの root で新しい Claude セッションを開き(curl -fsSL https://raw.githubusercontent.com/Rheinmir/setup/orca/harness/poc-vendor-neutral/bootstrap.sh | bash.claude/settings.jsonが読み込まれるようにします)、/harness-tourをもう一度入力します。
フックがブロックするのは、セッションがインストール済みの正しいプロジェクト root で
.claude/settings.jsonを読み込んだ場合のみです。ソースリポジトリ/ 別の root でセッションを開くと、フックがないため、ツアーは実演できません(ブロックされないまま実演するのは演出であり、禁止です)。
ハーネスは HOOK であり、MCP ではありません(ユーザーから「なぜ /mcp に表示されないのか」と聞かれた場合の説明)
ブロックするのは PreToolUse フックです。/hooks または .claude/settings.json の hooks ブロックで確認でき、/mcp には表示されません。
MCP は別のものです(モデルが呼び出すツールです)。PoC:フックが llmwiki-validate claude-hook を呼び出します。本番環境:pre_tool_use.py…
パス → ルール対応表(各シーンで 1 つのルールだけを発動させるため、正しいパスを使います)
複数のルールが wiki/ を検査するため、パスを間違えると 2 つのルールが同時にブロックし、混乱します。正しい対応表(policy.yaml に基づく):
| ルール | 違反させるファイル | そのルールだけが発動する理由 |
|---|---|---|
| R1 no-write-raw | llmwiki/raw/tour-demo.md | deny_write glob raw/** |
| R2 origin-required | llmwiki/wiki/sources/draft/tour-demo.md = ---\ntype: draft\n---\n# Tour Demo(frontmatter あり、## Origin なし、## Plan なし) | frontmatter があるため R9 は通過し、Origin がないため R2 がブロック |
| R3 index-sync | (Stop)R2 で作成したばかりのファイル。まだ wiki/index.md に含まれていません | m_stop が concepts/entities/sources/draft をスキャンし、index と照合します |
| R5 folder-structure | llmwiki/wiki/tour-demo.md(wiki/ 直下にある、許可リストにない basename) | forbid_root:wiki/*.md は許可リストに含まれていません |
| R7 proposal-complete | llmwiki/wiki/sources/draft/tour-demo-proposal.md — frontmatter、## Origin、## Plan、proposed はありますが、## Agent Task Assignment と Sequence diagram がありません | frontmatter があるため R9 は通過し、Origin があるため R2 も通過するので、R7 がブロックします |
| R9 okf-frontmatter | llmwiki/wiki/concepts/tour-demo.md — ## Origin はありますが、YAML frontmatter がありません | Origin があるため R2 は通過し、type: がないため R9 がブロックします |
⚠️ R9 は現在、
sources/とdraft/の両方を対象にしています(本番環境の全体設定と一致し、下書きにも frontmatter が必要です)。R2/R9 はどちらもすべての content dir を検査するため、パスではなく内容で分離します。frontmatter があり Origin がないファイル → R2 のみ。Origin があり frontmatter がないファイル → R9 のみ。
実行時にはブロックしないもの(アーティファクトを表示するだけで、「ブロックしない」と明示します):R4(.claude/audit/audit.jsonl + log.md)、
R8(SessionStart 時の [harness] N rule… の行)、R10(プロンプト数を記録する .claude/audit/.docs-gate.json)。
リポジトリ層:R6(pre-commit + CI .github/workflows/harness.yml + skill /verify-before-commit)。
ショートシナリオ(デフォルト)— 3シーン、順番に実演し、各シーンの前にナレーション
オープニング:「3つのルールにわざと違反してみます。フックがリアルタイムで止める様子を見てください。私が自分から引き下がるのではありません。」
シーン1 — R1(PreToolUse · raw/への書き込みを拒否):
- ナレーション:「raw/は人間用の受信箱です。エージェントは書き込めません。」
- Write
llmwiki/raw/tour-demo.md→ exit 2 → ブロック。stderr の[R1 no-write-raw] …を一字一句そのまま引用します。再試行しません。ファイルは作成されません。
シーン2 — R2(PreToolUse · ## Origin を必須化):
- ナレーション:「
## Originを『うっかり』忘れてソースファイルを作成すると、出典を追跡できません。」 - Write
llmwiki/wiki/sources/draft/tour-demo.md=---\ntype: draft\n---\n# Tour Demo(R9を通過するためfrontmatterは含めますが、## Originは含めません)→ exit 2 → ブロック。[R2 origin-required] …を引用します。 - 修正: 同じファイルに正しい内容を書き込み、
## Origin\n- harness-tour demoを追加します(frontmatterはそのまま維持)。今度はPASSし、ファイルが書き込まれます。
シーン3 — R3(Stop · インデックスの不整合):
- ナレーション:「作成したtour-demoファイルを、わざと
wiki/index.mdに記載しませんでした。ここでターンを終了してみます。」 - インデックスを更新せず、ここで応答を終了します → Stopフック(
harness-events.py stop)がexit 2を返し、不一致の一覧を表示します。 - ブロックされたら、
[R3 index-sync] wiki/index.md chưa liệt kê: …を一字一句そのまま引用し、wiki/index.mdにtour-demoの行を1行だけ追加してから、クリーンアップに進みます。
→ 続いてクリーンアップ(下記)。
フルシナリオ(ARGUMENTSにfullが含まれる場合)— R1~R10を順番に実演
リアルタイムでブロックされる6つのシーン(R1、R2、R3、R5、R7、R9)+ブロックせず成果物を見せる3つ(R4、R8、R10)+リポジトリの1つ(R6)を実演します。 ブロックしないルールのグループの前に、はっきりと伝えます:「次の3つのルールは入力時にブロックしません。記録・通知するルールです。証拠として成果物だけをお見せします。」
R1 — llmwiki/raw/tour-demo.mdにWrite → ブロック(raw/への書き込みを拒否)。引用して、再試行しません。
R2 — llmwiki/wiki/sources/draft/tour-demo.mdにWrite(R9を通過するためfrontmatter ---\ntype: draft\n---を含めますが、## Originは含めません)→ ブロック → ## Originを追加 → PASS。
R3 —(Stop) R2のファイルがまだindex.mdに追加されていない状態でターンを終了 → Stopでブロック → インデックスに行を追加 → 続行。
(FULLでは流れを保つため、R3を最後にまとめてもかまいません。以下のPASSするファイルを作成した後、インデックスに不整合が残った状態でターンを終了してみて、ブロックされたらインデックスを更新します。)
R4 — log-append(ブロックしない): WriteがPASSした後、.claude/audit/audit.jsonlに新しい行(tool+path+timestamp)が追加され、.claude/audit/log.mdが再生成されるだけです。末尾の数行をcatで表示して証拠を見せます。「記録するのはマシンです。私には削除できません。」
R5 — llmwiki/wiki/tour-demo.mdにWrite(wiki/直下)→ ブロック [R5 folder-structure] …(wikiのファイルはconcepts/entities/…以下に置く必要があります)。再試行しません。
R6 — verify-before-commit(リポジトリ、リアルタイムではブロックしない): コミットゲートが、pre-commitフック+CI .github/workflows/harness.yml(変更された.mdに対してコアのfiles modeを実行)+スキル/verify-before-commit(Claudeがコミット前に新しいコードを自ら確認する)で構成されていることを示します。これはリポジトリ層のルールであり、セッションではありません。直接ブロックを実演するものではありません。
R7 — llmwiki/wiki/sources/draft/tour-demo-proposal.mdにWrite(frontmatter、## Origin、## Plan、proposedを含めますが、## Agent Task AssignmentとSequence diagramは含めません)→ ブロック [R7 proposal-complete] … → 2つの項目を追加して修正 → PASS。
R8 — pattern-health(ブロックしない): python3 harness/poc-vendor-neutral/bin/harness-events.py sessionを実行し、[harness] N rule đang gác…の行を表示します(ポリシーとリモートにずれがあれば、ずれの警告も表示します)。これはSessionStartで出力されるものです。
R9 — llmwiki/wiki/concepts/tour-demo.mdにWrite(## Originは含めますが、YAML frontmatterは含めません)→ ブロック [R9 okf-frontmatter] …(typeがありません)→ 先頭に---\ntype: concept\n---を追加して修正 → PASS。
R10 — docs-gate(ブロックしない): cat .claude/audit/.docs-gate.jsonを実行し、プロンプトのカウンターを表示します。LLMWIKI_DOCS_GATE_EVERY(デフォルトは5)ターンごとに、UserPromptSubmitが/docs-site-macosの呼び出しを提案するディレクティブを挿入すると説明します。
FULLのまとめ: 10個のルールを表にまとめ、リアルタイムでブロックするもの、記録・通知するもの、リポジトリ層のものを示します。証拠として.claude/audit/*.jsonlを引用します。
クリーンアップ(必須 — 同じターン内で実施してください。そうしないと R3 にブロックされます)
PASS した(作成された)tour-demo* ファイルをすべて削除し、対応する wiki/index.md の行も同じターン内に削除してください
(ファイルだけ削除して行を残すと → index が不整合になり → Stop hook がクリーンアップのターンをブロックします):
- SHORT:
wiki/sources/draft/tour-demo.mdとその行。 - FULL:さらに
wiki/sources/draft/tour-demo-proposal.md、wiki/concepts/tour-demo.mdと各行。 - ブロックされたファイル(raw/tour-demo、wiki/tour-demo R5)は存在しないため、削除不要です。
- ハーネスの成果物(
audit.jsonl、log.md、.docs-gate.json)は正規のマシン記録です → そのまま残してください。削除しないでください。 - プロジェクトの既存ファイルには絶対に触れないでください。
締めくくり: 直前にブロックしたルールを1段落でまとめ、「直前のすべてのツール呼び出しは .claude/audit/*.jsonl に記録されています — マシンが記録したので、私は忘れられません」と記載してください(末尾数行を cat してください)。マシンが実行するデモはセッション不要です:bash harness/poc-vendor-neutral/demo.sh(13 assertions) · test-broad.sh(63)。
分岐
| ID | 種類 | ガード | 動作 | スキップ / 失敗 | 再合流 |
|---|---|---|---|---|---|
| B01 | user_optional | ARGUMENTS に full / 10 / " đầy đủ" | SHORT の代わりに FULL R1–R10 のシナリオを実行 | デフォルト → SHORT | W04 |
| B02 | conditional_required | pre-check が PROD を出力 | 同じように実行しますが、hook スクリプト名(pre_tool_use.py/post_tool_use.py/stop.py)のみ異なります。R1 は permissions.deny でブロックされる場合があります | — | W03 |
| B03 | recovery | pre-check が何も出力しない(MISSING) | 停止し、PoC の bootstrap.sh 用 curl コマンド(Pre-check ブロック)を提示してから、プロジェクトのルートで新しいセッションを開始するよう案内 | 実行しない | 終了 |
| B04 | user_optional | ユーザーが「/mcp が表示されないのはなぜ」と質問 | ハーネスは HOOK(/hooks を確認)であり、MCP ではないと説明 | — | W03 |
検証と停止
ライブブロックの各場面は、実際の hook が exit 2 を返し、stderr が原文のまま引用された場合にのみカウントします。ブロック後は再試行しません(指定された修正手順を除く)。ライブブロックのルールがブロックしなかった場合、ツアーは直ちに停止します。tour-demo* が残っておらず、wiki/index.md との整合性が取れたら完了です。
例
- 成功例: PoC をインストール済みのプロジェクトで
/harness-tourを実行 → pre-check がPOCを出力 →llmwiki/raw/tour-demo.mdへの Write が[R1 no-write-raw] …でブロック → R2 はブロック後、## Originを追加すると PASS → ターン終了時に Stop が[R3 index-sync] …でブロック → 行を追加 →wiki/sources/draft/tour-demo.mdとその行を同じターン内にクリーンアップ。 - 境界条件/失敗例: ソースリポジトリで
/harness-tour fullを開始(プロジェクトの.claude/settings.jsonは読み込まれない) → pre-check が何も出力しない → MISSING、停止し、curl bootstrap コマンドと新しいセッションの開始を案内します。どの場面も実行しません。