.claude/settings.jsonが満たすべき PreToolUse hook wiring の正本。bin/plangate doctor --check-settingsがこの契約と実体を突合する。 適用はscripts/apply-claude-settings.sh(ユーザー実行。AI は self-mod ガードで.claude/settings.jsonを編集できないため)。
| Hook | command(必須トークン) |
|---|---|
| EH-1 plan-exists | scripts/hooks/check-plan-exists.sh |
| EH-2 c3-approval | scripts/hooks/check-c3-approval.sh |
| EH-3 plan-hash | scripts/hooks/check-plan-hash.sh ${PLANGATE_HOOK_TASK:-} ${PLANGATE_HOOK_FILE:-} |
| EH-6 forbidden-files | scripts/hooks/check-forbidden-files.sh |
| EH-9 delegation-commit-boundary | scripts/hooks/check-delegation-commit-boundary.sh |
${PLANGATE_HOOK_FILE:-} を第2引数に含む(P4(d) ファイルパス
感応 SKIP / TASK-0070 AC-8。これが本セッション通底の未適用 wiring)。.claude/settings.json の PreToolUse command 群に
すべて存在すれば doctor --check-settings PASS。1 つでも欠落で FAIL。""(省略)/ "*" は全ツール発火として契約充足に数える。
この解釈は scripts/check-settings-wiring.sh の has() と
scripts/apply-claude-settings.sh の包含判定で一致させること。
片方だけが * を全ツールとみなすと、適用側は「配線済み」・検証側は
「不足」となり 何度適用しても収束しない(#928 で実害化)。bin/plangate doctor --check-settings(未適用箇所を列挙し非0)sh scripts/apply-claude-settings.sh(冪等。ユーザーが実行)⚠️ 適用スクリプトの副作用(本契約の範囲外):
apply-claude-settings.shは本契約が定める PreToolUse 6 項目だけでなく、.claude/settings.example.jsonの 全 hook event(SessionStart / PostToolUse / Stop を含む)を取り込む。 そこには契約外かつ副作用の大きい hook が含まれうる(例: SessionStart のscripts/gh-pin-account.shはgh auth switchでマシン全体の gh CLI active account を切り替える)。また「不足を足すが削除はしない」方針の 裏返しとして、example から意図的に削除した hook は再実行のたびに復活 する(opt-out 手段は現状なし)。--all-eventsopt-in 化は #975 で follow-up。
.claude/settings.json の AI 直接編集は禁止(self-mod ガード・恒久制約)。
AI は契約定義・検証・適用 script 提供まで。適用は人間。| 層 | 検証対象 | 手段 | 役割 |
|---|---|---|---|
CI settings-drift(required) |
.claude/settings.example.json(契約 reference) |
check-settings-wiring.sh --target example |
正本 reference が契約と乖離しないことを保証(example が壊れたら全員に波及するため) |
bin/plangate doctor --check-settings |
.claude/settings.json(ユーザー実体) |
構造(JSON)検証 | 実環境の wiring 未適用=Shadow Config を検出 |
既存 bin/plangate doctor hook-wiring check |
.claude/settings.json vs .claude/settings.example.json |
既存 check(TASK-0069) | settings.example.json を契約整合させた結果、未適用を通常 doctor でも FAIL(従来の false-PASS を是正) |
.claude/settings.json は gitignore(ユーザーローカル)のため CI では検出
不可。実体 drift の検出は doctor(ローカル / V-1・handoff DoD)が担う。
両者は役割が異なり、どちらか一方では「Shadow Config を構造的に防ぐ」根拠に
ならない(CI=reference 健全性 / doctor=実体適用)。
V-1/handoff 完了の DoD(docs/workflows/05_verify_and_handoff.md
/ working-context.md)に
「doctor --check-settings PASS」を必須化。強制は次の二重で成立する:
doctor の hook-wiring FAIL: settings.example.json を
契約整合させたため、未適用環境では bin/plangate doctor(通常実行)も
FAIL する。doctor FAIL 状態での完了報告は Iron Law(検証証拠なしに完了
扱いしない)違反。doctor --check-settings: 構造検証で未適用箇所を決定論的に列挙。
既知の限界(V2 候補):完全な PreToolUse-hook レベルの機械 block— 解消済 (PR #347)。.codex/hooks.json+.codex/hooks/eh-bridge.shで Codex CLI 側にも EH-1/2/3/6/9 が物理 PreToolUse block として配線済。Claude Code 側は従来通り.claude/settings.jsonで配線。詳細は本ファイル後段の §Codex CLI parity 参照。
model tier の parity: Claude Code は
.claude/agents/*.mdfrontmatter のmodel:(inherit/sonnet)、Codex は.codex/agents/*.tomlのmodel_reasoning_effort(low/medium)で同一の 2 tier を表現する。対応表の 正本はmodel-profiles.md§11。
判明事項 (2026-05-25 PR #347): OpenAI Codex CLI は PreToolUse / PostToolUse hook API を公式提供しており、Claude Code の hook 仕様と直接互換 (matcher / stdin JSON / exit 2 で deny / hookSpecificOutput.permissionDecision)。公式仕様: https://developers.openai.com/codex/hooks
| 層 | 機構 | カバー範囲 |
|---|---|---|
| 1. Session 前 | scripts/codex-guarded.sh (PR #343) |
validate / doctor / EH-8 privacy / plan.md hash snapshot |
| 2. Session 中 (物理 pre-Write block) | .codex/hooks.json + .codex/hooks/eh-bridge.sh (PR #347) |
EH-1 / EH-2 / EH-3 / EH-6 / EH-9 を Codex 側でも発火 |
| 3. Session 後 | scripts/codex-guarded.sh post-flight |
plan.md hash drift 検知 + validate 再実行 |
| 強制 | Claude Code | Codex CLI |
|---|---|---|
| EH-1 plan-exists | ✅ .claude/settings.json PreToolUse |
✅ .codex/hooks.json PreToolUse |
| EH-2 c3-approval | ✅ 同上 | ✅ 同上 |
| EH-3 plan_hash | ✅ 同上 | ✅ 同上 |
| EH-6 forbidden_files | ✅ 同上 | ✅ 同上 |
| EH-9 delegation-commit-boundary | ✅ PreToolUse Bash | ✅ PreToolUse Bash |
apply_patch / Edit / Write / Bash 呼び出し前に .codex/hooks.json を参照command (= .codex/hooks/eh-bridge.sh <HOOK_NAME>) が起動*** Update/Add/Delete File:) を抽出PLANGATE_HOOK_FILE / PLANGATE_HOOK_TASK を設定し scripts/hooks/<HOOK_NAME> を起動hookSpecificOutput.permissionDecision (allow / deny) に翻訳.claude/settings.json / bin/plangate / scripts/hooks/*.sh 等の Hardening Override 領域を改変するのは依然として AI 改変不可 (Human-owned).codex/hooks.json / .codex/hooks/*.sh) は AI-owned (Override 対象外)Status: Specification(方針確定。実装は HO パス絡みのため受け入れ条件ごとに段階 PBI へ分解) 出自: river 3 相レビュー(2026-06-08、Gemini + コードベース調査で代替実行 / external-reviewer-interface §10 unavailable 準拠)で検出した「規範↔実装」乖離 (Shadow Config)への是正方針。
settings.example.json は配布テンプレートのため warning モード(PLANGATE_HOOK_STRICT
未設定)を既定とし、導入直後の破壊を避ける。PLANGATE_HOOK_STRICT=1 を
設定し EH-2 / EH-3 / EH-6 等を block モードで動かす。bin/plangate doctor --check-settings は、コード整合性に加えて 現在のモードで必須
フックが strict 配線・有効化されているか を検証する。scripts/check-approval-token-write.sh(c3.json / maintenance.json 等の承認トークンへの
AI 書込みガード)を EH-10 として正規採番し、PreToolUse(Edit|Write) に配線する。PLANGATE_HOOK_FILE を自動 export しないため、.claude/settings.json の配線で ${PLANGATE_HOOK_FILE:-} を 引数として明示的に渡す(EH-3 と同様)。check-approval-token-write.sh は引数 $1 をターゲットファイルパスの fallback として受け取れるよう実装する(env のみ参照だと Claude Code 環境下でガードがスルーされる)。| 受け入れ条件 | 実装方針 | 主パス(HO) |
|---|---|---|
| EH-2(c3_status)strict 化 | EH-3 と同じ python3 strict JSON 解析へ置換(permissive な grep/sed 抽出を廃止し EH-3 と対称化) | scripts/hooks/check-c3-approval.sh |
| EH-1/EH-2 stdin fallback | env 未注入時に stdin tool_input.file_path から解決し SKIP(allow) を解消 |
scripts/hooks/*.sh |
| maintenance verdict テスト | VALID / CONSUMED / OUT_OF_SCOPE / HARDENING_OVERRIDE の fixture + assert を追加 | tests/hooks/ |
| ta-06 ログ握りつぶし解消 | >/dev/null 2>&1 圧縮をやめ、どの EH が落ちたかをログに残す |
tests/.../ta-06-hooks.sh |
本仕様の HO 実装は以下の順で段階 PBI に分解する(各々 plan → C-3 承認 👤 → exec、 HO 適用は Human):
scripts/check-settings-wiring.sh の checks リストにも EH-10(check-approval-token-write.sh)を追加し、CI / ローカルの契約ドリフト検知(--target example)に組み込んで配線漏れを防ぐ各段階は承認境界(HO)の変更を含むため mode-classification.md により最低 high・
Standard C-3 同期固定(autonomous APPROVE 無効)とする。
Status: Implemented(
scripts/apply-task-0143-eh457-wiring.sh --apply適用後に有効)
PreToolUse hook ではなく bin/plangate CLI サブコマンド経由で発火する配線。
| Hook | CLI 配線先 | 発火タイミング |
|---|---|---|
EH-4 (check-test-cases.sh) |
bin/plangate verify <TASK> |
V-1 実行前(strict=1、test-cases.md なしで block) |
EH-5 (check-verification-evidence.sh) |
bin/plangate verify <TASK> |
V-1 通過後(warn のみ、evidence なしで WARNING) |
EH-7 (check-merge-approvals.sh) |
手動呼び出し推奨 | merge 前: sh scripts/hooks/check-merge-approvals.sh <TASK> |
bin/plangate doctor の === CLI Hook Wiring (EH-4/5/7) === セクションが:
bin/plangate verify への配線状態(grep 確認)を PASS/WARN で報告# 差分確認(必須)
sh scripts/apply-task-0143-eh457-wiring.sh --dry-run
# 適用
sh scripts/apply-task-0143-eh457-wiring.sh --apply
適用後: bin/plangate doctor の出力で [PASS] EH-4 wired / [PASS] EH-5 wired を確認する。
Status: Implemented(
scripts/apply-task-0144-c3-mode.sh --apply適用後に有効)
.plangate.yml プロジェクト設定で C-3 承認モードを選択できる経路。
| モード | 動作 | c3.json の source フィールド |
|---|---|---|
cli(デフォルト) |
bin/plangate approve <TASK> で対話的に承認・c3.json 生成 |
"cli" |
conversation |
会話内で人間が APPROVE 発話 → AI が exec 前に c3.json を生成 | "conversation" |
approvals/c3.json + conversation mode → SKIP (exit 0)。c3.json の中身検証は EH-2 と AI 生成コードに委ねるscripts/hooks/check-plan-hash.sh に追加された判定:
target_file が docs/working/TASK-*/approvals/c3.json にマッチ.plangate.yml を読んで c3_approval.mode を取得conversation の場合 → EH-3_C3_CONVERSATION_SKIP をログに記録して exit 0(Write を許可)cli の場合 → 既存の maintenance / SKIP_REASON 判定に進む| ファイル | 種別 | 説明 |
|---|---|---|
.plangate.yml |
設定ファイル | プロジェクト設定(c3_approval.mode: cli\|conversation) |
schemas/plangate-config.schema.json |
Schema(HO) | .plangate.yml の JSON Schema 検証定義 |
schemas/c3-approval.schema.json |
Schema(HO 変更) | source フィールドを追加(optional) |
scripts/hooks/check-plan-hash.sh |
Hook(HO 変更) | conversation SKIP 経路を追加 |
bin/plangate |
CLI(HO 変更) | _read_plangate_config() 追加 / source: "cli" / doctor セクション追加 |
# 差分確認(必須)
sh scripts/apply-task-0144-c3-mode.sh
# 適用
sh scripts/apply-task-0144-c3-mode.sh --apply
適用後: bin/plangate doctor の出力で === C-3 Approval Mode === セクションを確認する。